Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Environment

Pattern

A reusable solution you can apply to your work.

Understand This First

  • Application – an environment is always an environment for something.

Context

This is an operational pattern that underpins everything else in this section. Before you can deploy, configure, test, or roll back software, you need to understand where it’s running. An environment is a particular runtime context: a combination of hardware (or cloud resources), software dependencies, configuration, and data where your Application executes.

Most projects have several environments: development (your laptop), test or CI (an automated build server), staging (a production-like system for final verification), and production (the real thing, serving real users). Each serves a different purpose and has different rules.

In agentic coding, the concept of environment matters immediately. The code an agent generates runs somewhere, and where it runs determines what databases it connects to, what APIs it calls, and whose data it touches.

Problem

Software that works on your machine fails in production. Tests pass locally but break in CI. A developer accidentally runs a migration against the production database. These problems all stem from the same root cause: environments aren’t clearly defined, separated, or respected. How do you create distinct, reliable contexts for developing, testing, and running software?

Forces

  • Developers want environments that are easy to set up and fast to iterate on.
  • Production needs stability, security, and monitoring that would slow down development.
  • Environments that differ too much from production hide bugs; environments that are too similar are expensive and complex.
  • Secrets, credentials, and data access must differ across environments. Production data should not leak into development.

Solution

Define and maintain distinct environments for each stage of your software lifecycle. At minimum, establish three: development (local or shared), a testing/CI environment, and production. Many teams add staging as a near-production environment for final validation.

Each environment should have its own Configuration: its own database, its own API keys, its own feature flags. The code should be identical across environments; only configuration should change. This is what makes environments useful: they let you run the same software under different conditions to catch problems before they reach users.

Protect production rigorously. Restrict access, require approvals for changes, and never share production credentials with development environments. Use Configuration patterns to make it hard to accidentally connect to the wrong environment.

When working with an AI agent, be explicit about which environment you are targeting. “Set up the database” is ambiguous. “Set up the local development database using Docker Compose with test seed data” is clear and safe.

How It Plays Out

A developer runs a data cleanup script. It works perfectly… against the production database, deleting real customer records. The team had been sharing a single database connection string across environments. After the incident, they set up isolated databases per environment, use environment variables to select the correct one, and add a confirmation prompt when any script detects it’s running against production.

A team uses Docker Compose to define their development environment: a web server, a database, and a message queue, all matching the production versions. New developers run docker compose up and have a working environment in minutes instead of a day of manual setup.

Warning

Environment parity is a spectrum, not a binary. Your development environment will never perfectly match production, and it shouldn’t try. The goal is to match closely enough that environment-specific bugs are rare, while keeping development fast and affordable.

Example Prompt

“Set up a Docker Compose file for local development with a web server, PostgreSQL, and Redis, matching the production versions. New developers should be able to run docker compose up and have a working environment.”

Consequences

Well-defined environments give teams confidence that code tested in one context will behave predictably in another. They prevent the most catastrophic class of operational errors: running the wrong thing in the wrong place. They also make onboarding easier, since new team members can set up a working development environment from documentation.

The cost is infrastructure complexity. Each environment needs resources, configuration, and maintenance. Keeping environments in sync as the system evolves requires ongoing effort. And the more environments you have, the more configuration you must manage, which leads naturally to the Configuration pattern.

  • Enables: Configuration — environments are differentiated primarily through configuration.
  • Enables: Deployment — deployment targets a specific environment.
  • Enables: Continuous Integration — CI runs in its own environment.
  • Depends on: Application — an environment is always an environment for something.