explainx.ainewsletter3.4k
trendingπŸ”₯loopsskills
pricing
workshops β†—
explainx.ai

Learn to lead teams that combine humans and agents. Platform access, live workshops, bootcamps, and 50+ courses β€” plus skills, tools, and MCP to practice what you learn.

follow us

custom AI agents

[email protected]

get started

Join Β· $29/mo

learn

start for freepathwaysworkshopsbootcampscoursescertificationscertification testsexplainx universitycorporate trainingfacilitatorshackathonslearn skills & mcp

discover

skillstoolsagentsmcp serversdesignsllmsagiranks

content

releasesvisionmissionaboutcommunityteamcareersresourcespromptsgenerators hubgenerator SEO hubprompt templatesprompt guidesblogfor LLMsdemo

Sister Products

Infloq

Infloq

Influencer marketing

BgBlur

BgBlur

Privacy-first blur

Olly Social

Olly Social

Social AI copilot

Ceptory

Ceptory

Video intelligence

BgRemover

BgRemover

Background removal

newsletter Β· weekly

Get AI news, tools, and insights in your inbox.

contactsupportprivacytermsdata rightssubmission guidelines

Β© 2026 AISOLO Technologies Pvt Ltd

← Back to blog

explainx / blog

What Are Environments in Software? Production, Staging, and Development Explained (2026)

Learn what software environments are, why production, staging, and development exist as separate instances, and how environment variables prevent the kind of mistakes that charge real users with test credit cards.

Jun 27, 2026Β·9 min readΒ·Yash Thakker
Web DevelopmentBeginners GuideDevOpsNext.js
What Are Environments in Software? Production, Staging, and Development Explained (2026)
Weekly digest3.4k readers

Catch up on AI

Curated AI updates on agents, skills, and MCP β€” delivered to your inbox. Unsubscribe anytime.

Every broken deployment has a story. Here is one of the most common ones.

A developer builds a payment flow over a weekend. They test it thoroughly in their local app using Stripe's test mode. The card 4242 4242 4242 4242 goes through cleanly. They push to production on Monday morning, confident it works. Within an hour, real users are complaining that payments are failing. The developer checks the logs and finds the problem immediately: the Stripe test key (sk_test_xxx) is still set in production. Real credit cards cannot be processed with a test key. Every transaction is silently rejected.

The fix is a one-line change. But the real lesson is architectural: development and production should never share configuration. That is what environments are for.


What an Environment Is

An environment is a separate, isolated instance of your application running with its own configuration, data, and infrastructure. When you open your project on your laptop and hit npm run dev, you are running in one environment. When a real user visits your site from their browser, they are hitting a completely different environment β€” different server, different database, different API keys.

The separation is intentional. It means a bug you introduce at 2 AM does not immediately break the product your paying customers are using. It means you can test a new feature against realistic data before it is visible to the world. It means the test credit card you just ran through checkout does not appear on a real bank statement.

Professional software teams typically maintain three environments.


The Three Standard Environments

Development (dev)

Development runs on your machine. It is yours to break. You can delete the database, push half-written code, enable verbose logging that prints every SQL query to the console, and crash the app twenty times before lunch. None of that affects anyone else.

Development typically uses:

  • A local database (PostgreSQL running on localhost:5432, or SQLite in a file)
  • Fake or seeded data β€” not real user information
  • Test API keys that do not process real money
  • Hot reload so the app refreshes automatically as you save files
  • Debug tools, error overlays, and source maps turned on

The goal of the development environment is speed. You want fast feedback loops. You do not care about performance, uptime, or data integrity the way you would in production.

Staging

Staging is the environment most beginners skip β€” and missing it is where expensive mistakes happen.

Staging mirrors production as closely as possible: same infrastructure, same build configuration, same environment variables (swapped for staging-specific values), same Docker image if you are using containers. But it is not public. Only your team can access it, usually behind a password or a VPN.

Staging is used for:

  • QA testing β€” your quality assurance team (or you, playing that role) runs through every user flow before a release
  • Testing with real-ish data β€” staging often uses an anonymised copy of the production database, so you are testing against realistic volume and variety
  • Catching integration issues β€” third-party APIs behave differently in staging than they do on localhost (webhooks, redirects, CORS headers)
  • Final review β€” product managers and designers sign off on a feature in staging before it goes live

The rule: if something passes in staging, it is ready for production. If you skip staging and go straight from dev to production, you are making a bet that your localhost environment perfectly matches the live server. It almost never does.

Production (prod)

Production is the live application. Real users, real data, real money. This is the environment where mistakes have consequences.

Production deployments follow strict rules at most companies:

  • Changes go through code review before they are merged
  • Automated tests must pass in CI before a deploy is allowed
  • Database migrations are run in maintenance windows or with backwards-compatible patterns (never drop a column without a two-step process)
  • Rollbacks are planned before deployments happen, not after

In production, debug mode is off. Error details are hidden from users (but logged to a monitoring service). Performance matters. Uptime matters.

The core principle: production is conservative. You do not experiment in production.


Environment Variables: The Glue

The mechanism that makes environments work is environment variables β€” key-value pairs that are set outside your code and change per environment.

Instead of writing this in your code:

const stripe = new Stripe('sk_live_my_real_key_that_charges_money');

You write:

const stripe = new Stripe(process.env.STRIPE_KEY);

And then you define STRIPE_KEY separately in each environment. In development it is the test key. In production it is the live key. Your code never changes β€” only the value injected at runtime.

A .env file for development might look like this:

DATABASE_URL=postgresql://localhost:5432/myapp_dev
STRIPE_KEY=sk_test_xxx
ANTHROPIC_API_KEY=sk-ant-xxx
NEXT_PUBLIC_APP_URL=http://localhost:3000

And the production environment would have:

DATABASE_URL=postgresql://prod-server/myapp_prod
STRIPE_KEY=sk_live_xxx
NEXT_PUBLIC_APP_URL=https://myapp.com

The database URL points to different servers. The Stripe key switches from test to live. The app URL is the real domain instead of localhost. Same code, completely different runtime behavior.


The .env File in Next.js

If you are building with Next.js, the standard pattern is to use .env.local for your local development secrets. Next.js loads it automatically when you run next dev.

The naming convention matters:

  • .env β€” checked into git, used for non-secret defaults
  • .env.local β€” never committed, used for local secrets (overrides .env)
  • .env.production β€” checked into git, used for non-secret production defaults
  • .env.production.local β€” never committed, used for production secrets

Variables prefixed with NEXT_PUBLIC_ are exposed to the browser. Everything else stays server-side only. Never put a secret API key in a NEXT_PUBLIC_ variable β€” it will be bundled into the JavaScript file that every visitor downloads.


Why .env Must Be in .gitignore

The single most important rule about .env files: they must never be committed to version control.

Add this to your .gitignore:

.env
.env.local
.env.*.local

If a .env file with real API keys lands in a public GitHub repository, automated bots find it within minutes. Those bots are scanning GitHub continuously for leaked credentials. Once a key is exposed in git history, you must rotate it immediately β€” not delete the file, because the key is still in the commit history. Rotate it. Then delete the file and add it to .gitignore.


Feature Flags: Deploying Without Releasing

Some teams take environment separation further with feature flags. A feature flag is a configuration toggle that lets you deploy code to production but hide it from most users. You might deploy a new dashboard design but only show it to internal employees until it is polished. Or you might roll it out to 5% of users, watch the error rate, and expand the rollout if everything looks healthy.

Feature flags decouple deployment (pushing code to the server) from release (making a feature visible to users). This is safer than combining both into one step.

Tools like LaunchDarkly, Unleash, and PostHog feature flags implement this pattern. For smaller projects, a simple environment variable or a database row can serve as a basic flag.


How Code Flows Between Environments

A typical CI/CD (Continuous Integration / Continuous Deployment) pipeline works like this:

  1. You push a branch to GitHub and open a pull request
  2. The CI system (GitHub Actions, CircleCI) runs your automated tests
  3. If tests pass, the branch is deployed automatically to the staging environment
  4. Your team reviews the feature in staging
  5. The pull request is merged to the main branch
  6. The CI/CD pipeline deploys the main branch to production

Each step is a gate. Broken tests block deployment to staging. A failed staging review blocks the merge. The goal is to catch problems as early as possible β€” in development, then in staging β€” so production stays clean.

If you are learning git and GitHub and want to understand how to push your code in the first place, the beginner guide to Git and GitHub covers that foundation.


Common Mistakes Beginners Make

Running database migrations directly in production. Always test migrations in staging first. A migration that drops a column, renames a table, or changes a data type can break a running app in unpredictable ways. Staging is where you discover that.

Using production API keys in development. If you use your live Stripe key locally and accidentally process a test charge, you may create accounting noise, trigger fraud detection, or incur unexpected fees. Always use test keys in development.

Committing secrets to git. Covered above, but worth repeating. Add .env.local to .gitignore before you create the file, not after.

Not having a staging environment at all. This feels fine until the first time you deploy a bug that was obvious when someone looked at it in a browser. Staging is cheap (or free on most platforms). The bugs it catches are not.

Assuming localhost behavior matches production. HTTPS redirects, cookie Secure flags, CORS headers, and environment-specific webhook URLs all behave differently locally. Staging with a real domain reveals these issues before production does.


Quick Reference

DevelopmentStagingProduction
Who uses itYou (developer)Your team, QAReal users
DataFake / seededAnonymised copy of prodReal user data
API keysTest keysTest or staging keysLive keys
Errors shownFull detail, stack tracesInternal onlyHidden from users
Stability neededLow β€” break freelyMediumHigh
DeploymentsConstantOn each PR mergeDeliberate, reviewed

Understanding environments is one of those concepts that clicks quietly but then suddenly explains a dozen things that were confusing before β€” why .gitignore exists, why there are multiple database URLs in a config file, why the QA team has a separate website to test on. Once you see the separation, you start building with it from day one.

Weekly digest3.4k readers

Catch up on AI

Curated AI updates on agents, skills, and MCP β€” delivered to your inbox. Unsubscribe anytime.

Related posts

Jun 27, 2026

What is Vercel? How to Deploy Your App in Minutes (2026 Beginner Guide)

Vercel takes your Next.js app from GitHub to a live URL in about sixty seconds. Here is exactly how it works, what it handles for you, how to configure environment variables for production, and when the free tier stops being enough.

Jun 27, 2026

What is Next.js? How to Install and Build Your First Next.js Project (2026)

Next.js from zero: what it is, why people use it, how to install it with create-next-app, and how to build your first pages with the App Router. Real commands, no assumed knowledge.

Jun 27, 2026

What is Railway? How to Deploy Apps and Databases in Minutes (2026 Guide)

Railway is where you deploy the parts of your stack that need to stay running: PostgreSQL databases, background workers, WebSocket servers, and Python backends. Here is a practical walkthrough of deploying an app, adding a database, wiring environment variables, and understanding when to use Railway instead of Vercel.