Environment variables on Prostack Cito

On Vercel or Netlify you set environment variables in a dashboard, per environment. On Prostack Cito they live in a .env file in the site’s folder, owned by the site’s user. It stays put across deploys, and your app reads it the way it would on your laptop.

Updated · All guides

Where they live

Each site has its own system user and its own folder, ~/public_html by default. Put a file called .env there, next to package.json or artisan:

# ~/public_html/.env
DATABASE_URL="postgresql://app:[email protected]/app"
STRIPE_SECRET_KEY="sk_live_..."
NEXT_PUBLIC_SITE_URL="https://example.com"

Create it over SSH as the site’s user, or with the File Manager in the site’s settings. Keep it out of git by adding it to .gitignore: the file belongs to the server, and the repository shouldn’t know its values.

There’s no separate “production” and “preview” set, as there is on Vercel. A site has one .env, and a staging site is a separate site with its own (see staging below).

Why they survive deploys

A Git deploy doesn’t start from an empty folder. Cito copies the live site, pulls the new commit into the copy and swaps it in, so anything that isn’t in git, .env included, comes along. You set a value once and it stays until you change it.

Deploys through the Cito MCP server work the other way round: they upload your project from your machine, and they leave out any file called .env so your local values can’t overwrite the server’s.

Next.js

Next.js reads .env itself, when it builds and when the app starts, so there’s nothing to add to app.js. What changes is when each kind of value takes effect.

  • NEXT_PUBLIC_ values are fixed at build time. Next.js writes them into the JavaScript it sends to the browser. Change one and nothing happens until the next build.

  • Other values are read when the app starts. Change one, then restart the app:

    passenger-config restart-app ~/public_html
    
  • Keep .env.local off the server. Next.js reads .env.local and .env.production.local ahead of .env. The MCP deploy only leaves out a file called exactly .env, so a .env.local in the folder you deploy from would be uploaded and quietly override the server’s values. Keep local files out of that folder, or out of the deploy.

Other Node apps

Node 24 can load a .env file without any packages. Do it at the top of app.js, before anything reads process.env:

process.loadEnvFile('.env');

If the app already uses dotenv, that works too. Either way, a changed value takes effect when the app restarts.

Laravel and other PHP apps

Laravel reads .env as usual. If you cache the config in production, Laravel stops reading .env until you rebuild the cache, so after changing a value run one of these as the site’s user:

php artisan config:clear   # read .env directly again
php artisan config:cache   # or rebuild the cache with the new value

Staging and live

When you clone a site to make a staging copy, the clone takes the live site’s files, and that includes its .env. Cito can clone the database too, with a new database user, and its auto-reconfigure option updates some apps’ config files to match. Don’t rely on it for .env: check it yourself, because a clone that still holds the live settings talks to live services.

Before you use a staging copy, open its .env and change:

  • the database connection, to the cloned database Cito created;
  • API keys, to test keys where the provider has them (Stripe’s sk_test_ keys, for example);
  • anything that sends email, texts or webhooks to real people.

Otherwise a test on staging can charge a real card or email a real customer.

Keeping them safe

Make the file readable by the site’s own user only:

chmod 600 ~/public_html/.env

If a key has ever been committed to git, deleting the file isn’t enough: it’s still in the repository’s history, and anyone with access to the repository can read it. Roll the key with the provider first, then clean up. The readiness audit checks your history for exactly this.

More guides

Everything in the Cito control panel, setting by setting, is in the Cito documentation.

Rather we did the move?

If your app runs on Prostack Cito as it is, we move it for you, free.