Advanced

Environment Variables

Managing environment variables, MANIC_PUBLIC_ prefix rules, and configuration in Manic.

Environment Variables

TL;DR

Manic uses environment variables for configuration. Variables prefixed with MANIC_PUBLIC_ are exposed to the client, while server-only variables remain protected. Use .env files for different environments.

What It Is

Environment variables in Manic follow a prefix-based visibility model:

PrefixClient VisibleServer VisibleUse Case
MANIC_PUBLIC_✓ Yes✓ YesPublic config
None✗ No✓ YesPrivate keys

Special files:

  • .env - All environments
  • .env.local - Local only (not committed)
  • .env.development - Dev only
  • .env.production - Production only

Prerequisites


Quick Start

1. Create .env file

# .env.local (never committed)
MANIC_PUBLIC_API_URL=https://api.example.com
API_SECRET=sk-1234567890

2. Use in code

import { getEnv } from 'manicjs/env';

// Client-safe (MANIC_PUBLIC_*)
console.log(getEnv('MANIC_PUBLIC_API_URL'));

// Server-only
// console.log(getEnv('API_SECRET'));  // ✗ Undefined on client

How It Works

Environment Loading Flow

Initializing diagram...

Variable Visibility

Initializing diagram...

Type Definitions

// Manic environment types
interface ManicEnv {
  // Public (MANIC_PUBLIC_*)
  MANIC_PUBLIC_API_URL?: string;
  MANIC_PUBLIC_TITLE?: string;

  // Private
  API_SECRET?: string;
  DATABASE_URL?: string;
}

API Reference

getEnv(key: string)

Primary helper for accessing environment variables in both client and server code.

import { getEnv } from 'manicjs/env';

// Public variables (MANIC_PUBLIC_*) are available everywhere
const apiUrl = getEnv('MANIC_PUBLIC_API_URL');

// Private variables are ONLY available on the server
const secret = getEnv('API_SECRET');

Accessing in Components

import { getEnv } from 'manicjs/env';

export function MyComponent() {
  const apiUrl = getEnv('MANIC_PUBLIC_API_URL');

  return <div>API: {apiUrl}</div>;
}

Examples

Example 1: API Configuration

# .env
MANIC_PUBLIC_API_URL=https://api.example.com

# .env.local (local development)
MANIC_PUBLIC_API_URL=http://localhost:3001
// app/routes/api/client.ts
import { getEnv } from 'manicjs/env';

export const apiClient = {
  baseUrl: getEnv('MANIC_PUBLIC_API_URL') || 'https://api.example.com',
};

Example 2: Feature Flags

# .env
MANIC_PUBLIC_ENABLE_BETA=false

# .env.local
MANIC_PUBLIC_ENABLE_BETA=true
import { getEnv } from 'manicjs/env';

export function BetaFeature() {
  if (getEnv('MANIC_PUBLIC_ENABLE_BETA') !== 'true') {
    return null;
  }

  return <div>Beta feature enabled!</div>;
}

Example 3: Third-Party Services

# .env.local
MANIC_PUBLIC_STRIPE_PUBLIC_KEY=pk_test_xxx
STRIPE_SECRET_KEY=sk_test_xxx
// Stripe on client
import { loadStripe } from '@stripe/stripe-js';
import { getEnv } from 'manicjs/env';

const stripePromise = loadStripe(
  getEnv('MANIC_PUBLIC_STRIPE_PUBLIC_KEY')
);
// Stripe on server (API route)
// app/api/payment/index.ts
import { getEnv } from 'manicjs/env';

const stripe = require('stripe')(
  getEnv('STRIPE_SECRET_KEY')
);

Example 4: Database URL

# .env.local (not committed)
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
// app/api/db.ts
// Server-only access
import { getEnv } from 'manicjs/env';

const dbUrl = getEnv('DATABASE_URL');

Never expose database URLs or other sensitive secrets in MANIC_PUBLIC_ prefixed variables. These are baked into the client bundle and visible to anyone.


Advanced Patterns

Pattern 1: Type-Safe Environment

// env.d.ts
interface Environment {
  MANIC_PUBLIC_API_URL: string;
  MANIC_PUBLIC_APP_NAME: string;
  MANIC_PUBLIC_ENABLE_BETA: string;
}

declare module 'manicjs/env' {
  export function getEnv<T extends keyof Environment>(key: T): Environment[T];
}

Pattern 2: Validation

// app/routes/~lib/env.ts
import { getEnv } from 'manicjs/env';

function getRequiredEnv(key: string): string {
  const value = getEnv(key);
  if (!value) {
    throw new Error(`Missing required env: ${key}`);
  }
  return value;
}

export const API_URL = getRequiredEnv('MANIC_PUBLIC_API_URL');

Common Issues

Issue 1: Variable Undefined

Problem: getEnv('MANIC_PUBLIC_XXX') is undefined.

Checks:

  1. Variable is in .env file
  2. File is in correct location
  3. Server was restarted after changes

Solution:

# .env must be in project root
# ✓ /my-app/.env
# ✗ /my-app/app/.env

Issue 2: Variables Exposed to Client

Problem: Private variables visible in browser.

Solution: Remove MANIC_PUBLIC_ prefix:

# ✗ BAD: Exposed to client
MANIC_PUBLIC_SECRET=xxx

# ✓ GOOD: Server-only
SECRET=xxx

Security Best Practices

Never commit secrets — always add .env.local and other sensitive environment files to your .gitignore.

Use MANIC_PUBLIC_ prefix only for variables that are safe to expose to the client.

Validate required variables at startup to ensure your application doesn't fail silently at runtime.

Use different files for different environments.


File Precedence

When multiple files define the same variable:

Higher priority (overrides):
1. .env.local
2. .env.development / .env.production
3. .env

Lower priority:

See also:

On this page