Skip to main content
RapidDev - Software Development Agency
replit-tutorial

How to store secrets safely in Replit

Replit stores secrets as AES-256 encrypted environment variables in the Secrets panel (Tools > Secrets). Add secrets through the App Secrets tab for per-project keys or Account Secrets for cross-project keys. Access them in Node.js with process.env.KEY_NAME and in Python with os.getenv('KEY_NAME'). Critical rule: workspace secrets do not carry to deployments automatically. You must add them separately in the Deployments pane. This is the number one cause of deployed apps failing with undefined values.

What you'll learn

  • Add and manage secrets using the Replit Secrets panel UI
  • Access secrets in Node.js, Python, and other supported languages
  • Configure deployment secrets separately from workspace secrets
  • Understand visibility rules: what collaborators, visitors, and forkers can see
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate9 min read10 minutesAll Replit plans (Starter, Core, Pro, Enterprise). Secrets are NOT available in Static Deployments.March 2026RapidDev Engineering Team
TL;DR

Replit stores secrets as AES-256 encrypted environment variables in the Secrets panel (Tools > Secrets). Add secrets through the App Secrets tab for per-project keys or Account Secrets for cross-project keys. Access them in Node.js with process.env.KEY_NAME and in Python with os.getenv('KEY_NAME'). Critical rule: workspace secrets do not carry to deployments automatically. You must add them separately in the Deployments pane. This is the number one cause of deployed apps failing with undefined values.

Store and Manage Secrets Safely in Your Replit Projects

This tutorial is a comprehensive walkthrough of the Replit Secrets panel. You will learn how to add secrets through the UI, access them in code across multiple languages, understand visibility rules (who can see what), configure deployment secrets separately, and use bulk editing features. This is essential knowledge for any Replit project that connects to external services, databases, or APIs. The guide is aimed at intermediate developers who want to follow security best practices from the start.

Prerequisites

  • A Replit account with an active Repl
  • At least one API key or token you need to store securely
  • Basic understanding of environment variables

Step-by-step guide

1

Open the Secrets panel in the workspace

In your Replit workspace, locate the Tools dock on the left sidebar. Click on Secrets to open the panel. If Secrets is not visible in the dock, click the search icon at the top of the sidebar and type Secrets. The Secrets panel has two tabs: App Secrets (specific to the current Repl) and Account Secrets (available across all your Repls, but must be linked to individual apps before use). For most use cases, you will use App Secrets.

Expected result: The Secrets panel is open showing App Secrets and Account Secrets tabs.

2

Add your first secret

In the App Secrets tab, click the plus button or the Add Secret button. Enter a key name using uppercase letters and underscores (this is a convention, not a requirement). For example: OPENAI_API_KEY, DATABASE_URL, or STRIPE_SECRET_KEY. Paste the secret value in the value field. Click Add Secret. The value is immediately encrypted with AES-256 encryption and stored securely. You can add as many secrets as your project needs. Each secret is a key-value pair that becomes an environment variable at runtime.

Expected result: Your secret appears in the list with the key name visible and the value hidden by default.

3

Access secrets in your code

Secrets are injected as standard environment variables at runtime. Access them using the native environment variable API for your programming language. In Node.js, use process.env.KEY_NAME. In Python, use os.getenv('KEY_NAME') or os.environ['KEY_NAME']. The difference in Python: os.getenv returns None if the variable is missing, while os.environ raises a KeyError. For production code, always check that the value exists before using it to avoid runtime crashes.

typescript
1// Node.js
2const apiKey = process.env.OPENAI_API_KEY;
3if (!apiKey) {
4 throw new Error('OPENAI_API_KEY is not set. Add it in Tools > Secrets.');
5}
6
7// Python
8import os
9api_key = os.getenv('OPENAI_API_KEY')
10if not api_key:
11 raise ValueError('OPENAI_API_KEY is not set. Add it in Tools > Secrets.')
12
13// Rust
14let api_key = std::env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY not set");
15
16// Go
17apiKey := os.Getenv("OPENAI_API_KEY")
18
19// Ruby
20api_key = ENV["OPENAI_API_KEY"]
21
22// Java
23String apiKey = System.getenv("OPENAI_API_KEY");

Expected result: Your code accesses the secret value and uses it for API authentication or configuration.

4

Configure deployment secrets separately

This is the most critical step that most users miss. Workspace secrets are only available in the development environment when you click Run. When you deploy your app (Autoscale, Reserved VM, or Scheduled), you must add the same secrets separately in the Deployments pane. Open the Deployments tab, find the Secrets section, and add each secret. The values can differ between workspace and deployment (for example, test keys vs production keys). If you skip this step, process.env.KEY_NAME returns undefined in the deployed app, which is the number one cause of deployment failures on Replit.

Expected result: All required secrets are configured in both the workspace Secrets panel and the Deployments Secrets section.

5

Use bulk editing for multiple secrets

When migrating from another platform or adding many secrets at once, use the bulk editing feature. In the Secrets panel, click Edit as JSON to enter secrets in JSON format or Edit as .env to paste a standard .env file format. The JSON format accepts an object with key-value pairs. The .env format accepts KEY=VALUE lines, one per line. This is much faster than adding secrets one at a time, especially when migrating from a local development setup that uses .env files.

typescript
1// JSON format for bulk entry
2{
3 "OPENAI_API_KEY": "sk-abc123",
4 "DATABASE_URL": "postgresql://user:pass@host:5432/db",
5 "STRIPE_SECRET_KEY": "sk_test_xyz789",
6 "JWT_SECRET": "your-jwt-secret-here"
7}
8
9// .env format for bulk entry
10OPENAI_API_KEY=sk-abc123
11DATABASE_URL=postgresql://user:pass@host:5432/db
12STRIPE_SECRET_KEY=sk_test_xyz789
13JWT_SECRET=your-jwt-secret-here

Expected result: Multiple secrets are added at once through the bulk editor.

6

Understand visibility and access rules

Different users see different levels of secret information. Collaborators with edit access can see both secret names and values. Cover page visitors (anyone viewing your public Repl) see nothing from the Secrets panel. Users who fork (remix) your Repl see secret names but not values, so they know which secrets to add but cannot access your credentials. Organization members without the Owner role cannot view values in the UI but can print them via code. Understanding these rules is essential for teams. For enterprise teams with complex access control requirements, RapidDev can help implement granular permission systems.

Expected result: You understand who can see your secrets and plan your sharing and collaboration accordingly.

7

Handle predefined environment variables

Replit automatically sets several environment variables you can use in your code without adding them to Secrets. REPLIT_DEPLOYMENT is set to 1 in deployed apps (undefined in workspace). REPLIT_DOMAINS contains your app's domain. REPL_ID is the unique identifier for your Repl. REPL_SLUG is the project name. REPL_OWNER is the username. REPLIT_DB_URL is the connection string for Replit DB. Important: REPLIT_DEV_DOMAIN exists only in the workspace and is NOT available in deployments. Do not rely on it for production logic.

typescript
1// Check predefined variables
2console.log('Deployment:', process.env.REPLIT_DEPLOYMENT || 'workspace');
3console.log('Domain:', process.env.REPLIT_DOMAINS);
4console.log('Repl ID:', process.env.REPL_ID);
5console.log('Owner:', process.env.REPL_OWNER);
6console.log('Slug:', process.env.REPL_SLUG);
7
8// Use REPLIT_DEPLOYMENT for environment detection
9const isProduction = process.env.REPLIT_DEPLOYMENT === '1';

Expected result: You can access predefined variables and use REPLIT_DEPLOYMENT to distinguish between workspace and deployed environments.

Complete working example

config.js
1/**
2 * Secure configuration module for Replit projects
3 * All secrets stored in Tools > Secrets (workspace) and Deployments > Secrets (production)
4 *
5 * Visibility rules:
6 * - Collaborators: see names + values
7 * - Cover page visitors: see nothing
8 * - Forkers: see names only (must add own values)
9 */
10
11const isProduction = process.env.REPLIT_DEPLOYMENT === '1';
12
13// Define all required and optional secrets
14const REQUIRED_SECRETS = [
15 'DATABASE_URL',
16 'JWT_SECRET',
17];
18
19const OPTIONAL_SECRETS = [
20 'OPENAI_API_KEY',
21 'STRIPE_SECRET_KEY',
22 'SENDGRID_API_KEY',
23];
24
25// Validate required secrets at startup
26const missing = REQUIRED_SECRETS.filter(key => !process.env[key]);
27if (missing.length > 0) {
28 const location = isProduction ? 'Deployments > Secrets' : 'Tools > Secrets';
29 console.error(`Missing required secrets in ${location}: ${missing.join(', ')}`);
30 if (isProduction) {
31 process.exit(1);
32 }
33}
34
35// Warn about missing optional secrets
36const missingOptional = OPTIONAL_SECRETS.filter(key => !process.env[key]);
37if (missingOptional.length > 0) {
38 console.warn(`Optional secrets not set: ${missingOptional.join(', ')}`);
39}
40
41const config = {
42 environment: isProduction ? 'production' : 'development',
43 port: parseInt(process.env.PORT || '3000', 10),
44 database: {
45 url: process.env.DATABASE_URL,
46 },
47 jwt: {
48 secret: process.env.JWT_SECRET,
49 expiresIn: '24h',
50 },
51 openai: {
52 apiKey: process.env.OPENAI_API_KEY || null,
53 },
54 stripe: {
55 secretKey: process.env.STRIPE_SECRET_KEY || null,
56 },
57 replit: {
58 domains: process.env.REPLIT_DOMAINS,
59 replId: process.env.REPL_ID,
60 owner: process.env.REPL_OWNER,
61 },
62};
63
64console.log(`Config loaded for ${config.environment}`);
65
66module.exports = config;

Common mistakes when storing secrets safely in Replit

Why it's a problem: Adding secrets only in the workspace Secrets panel and expecting them to work in deployments

How to avoid: Workspace and deployment secrets are separate. After adding secrets in Tools > Secrets, also add them in the Deployments pane under the Secrets section. This is the number one deployment failure cause.

Why it's a problem: Using a .env file in Replit instead of the Secrets panel

How to avoid: Delete the .env file and use the Secrets panel exclusively. .env files are visible in public Repls and are not encrypted. The Secrets panel uses AES-256 encryption.

Why it's a problem: Expecting secrets to be available in Static Deployments

How to avoid: Static Deployments serve HTML/CSS/JS only and do not support runtime environment variables. Use Autoscale, Reserved VM, or Scheduled deployments if your app needs secrets.

Why it's a problem: Not restarting the app after adding a new secret

How to avoid: Secrets added while the app is running may not be picked up by the current process. Click Stop then Run to restart, or run kill 1 in Shell to reload the environment.

Why it's a problem: Relying on REPLIT_DEV_DOMAIN in deployed apps

How to avoid: REPLIT_DEV_DOMAIN only exists in the workspace. It is undefined in deployments. Use REPLIT_DOMAINS instead, which works in both environments.

Best practices

  • Add secrets to the Secrets panel from day one, never start with hardcoded values even during prototyping
  • Always add deployment secrets separately from workspace secrets in the Deployments pane
  • Validate required secrets at application startup and fail fast with clear error messages
  • Use REPLIT_DEPLOYMENT to distinguish between workspace and deployed environments
  • Rotate secrets immediately after removing a collaborator from your project
  • Use the Edit as JSON or Edit as .env feature for bulk secret entry when migrating platforms
  • Never log secret values, even in development. Log only whether a secret is set or missing.
  • Remember that secrets are NOT available in Static Deployments. Use Autoscale, Reserved VM, or Scheduled.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am setting up a Replit project that uses [list of APIs/services]. Show me how to: 1) Add secrets in the Replit Secrets panel, 2) Create a config.js module that accesses and validates all secrets, 3) Handle the difference between workspace and deployment secrets, 4) Use REPLIT_DEPLOYMENT to switch between test and production credentials.

Replit Prompt

Set up secure secrets management for my project. I need to store API keys for [services]. Create a configuration module that validates all required secrets at startup, handles missing secrets gracefully, and detects whether the app is running in development or production using REPLIT_DEPLOYMENT.

Frequently asked questions

Yes. Replit encrypts all secrets with AES-256 encryption and transmits them over TLS. Values are decrypted only at runtime when accessed through environment variables.

Workspace secrets do not automatically carry to deployments. You must add them separately in the Deployments pane under the Secrets section. This is the most common cause of deployment failures on Replit.

No. Cover page visitors cannot see any information from the Secrets panel. However, if you hardcoded secrets in your source code files, those are visible to everyone. Always use the Secrets panel.

Forkers see secret names but not values. They know which secrets to create for the forked project to work, but they must provide their own API keys and credentials.

No. Static Deployments serve HTML, CSS, and JavaScript files only. They do not support runtime environment variables. If your app needs secrets, use an Autoscale, Reserved VM, or Scheduled deployment instead.

After adding a secret, run kill 1 in Shell to reload the environment. Then use echo $SECRET_NAME to verify the value. Without the restart, the current Shell session may not have the new secret available.

Yes. RapidDev can help design secure credential management architectures including multi-environment configurations, secret rotation strategies, and integration patterns for teams working on production Replit projects.

App Secrets are specific to one Repl. Account Secrets are stored at your account level and can be linked to multiple Repls, which is useful for credentials shared across projects like a database connection string.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.