Agent skill
solidstart-environment
SolidStart environment variables: VITE_ prefix for public variables, process.env for server-only, .env files, type safety with env.d.ts, runtime vs build-time variables.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/solidstart-environment
Metadata
Additional technical details for this skill
- globs
-
[ "**/.env*", "**/env.d.ts", "**/*env*" ]
SKILL.md
SolidStart Environment Variables
Complete guide to managing environment variables in SolidStart. Understand the difference between public (client-side) and private (server-only) variables.
Public Environment Variables
Public variables are safe to expose to client-side code. They must be prefixed with VITE_ and are injected during build time.
Basic Setup
Create a .env file in the project root:
VITE_API_URL=https://api.example.com
VITE_APP_NAME=My App
VITE_USER_ID=123
Access in client code:
function MyComponent() {
return (
<div>
<h2>API: {import.meta.env.VITE_API_URL}</h2>
<p>App: {import.meta.env.VITE_APP_NAME}</p>
</div>
);
}
Key points:
- Must use
VITE_prefix - Injected at build time
- Available in client code
- Access via
import.meta.env.VITE_*
Type Safety
Create env.d.ts for TypeScript autocomplete:
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_APP_NAME: string;
readonly VITE_USER_ID: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
Now TypeScript will autocomplete and type-check your environment variables.
Private Environment Variables
Private variables are server-only and should NOT use the VITE_ prefix. Access them via process.env in server code.
Basic Setup
DB_HOST=somedb://192.110.0
DB_PASSWORD=super_secret_password_hash
API_SECRET_KEY=secret123
Access in server code:
"use server";
export async function getData() {
const client = new DB({
host: process.env.DB_HOST,
password: process.env.DB_PASSWORD,
});
// Use private variables
const apiKey = process.env.API_SECRET_KEY;
return client.query();
}
Key points:
- NO
VITE_prefix - Only accessible in server code
- Use
process.envto access - Not exposed to client
Type Safety for Server Variables
Add to env.d.ts:
declare namespace NodeJS {
interface ProcessEnv {
readonly DB_HOST: string;
readonly DB_PASSWORD: string;
readonly API_SECRET_KEY: string;
}
}
Environment Files
Development (.env)
VITE_API_URL=http://localhost:3000
DB_HOST=localhost
DB_PASSWORD=dev_password
Production (.env.production)
VITE_API_URL=https://api.production.com
DB_HOST=prod-db.example.com
DB_PASSWORD=prod_secret_password
Local Override (.env.local)
# Overrides .env, not committed to git
VITE_API_URL=http://localhost:4000
File priority (highest to lowest):
.env.local(always loaded, ignored by git).env.[mode].local(e.g.,.env.production.local).env.[mode](e.g.,.env.production).env
Security Best Practices
❌ Never Expose Secrets
# ❌ WRONG - This will be exposed to client!
VITE_DB_PASSWORD=secret123
# ✅ CORRECT - No VITE_ prefix
DB_PASSWORD=secret123
✅ Verify Client Exposure
// Check what's exposed
console.log(import.meta.env.VITE_SECRET_KEY); // ✅ Exposed (if prefixed)
console.log(import.meta.env.DB_PASSWORD); // ✅ undefined (safe)
✅ Use Server Actions for Secrets
// ❌ WRONG - Exposes API key to client
function ClientComponent() {
const apiKey = import.meta.env.VITE_API_KEY; // Exposed!
fetch(`/api?key=${apiKey}`);
}
// ✅ CORRECT - Keep secret on server
"use server";
export async function fetchData() {
const apiKey = process.env.API_SECRET_KEY; // Server-only
return fetch(`/api?key=${apiKey}`);
}
Runtime vs Build-Time
Build-Time Variables (VITE_*)
// Replaced at build time
const apiUrl = import.meta.env.VITE_API_URL;
// After build: const apiUrl = "https://api.example.com";
Characteristics:
- Replaced during build
- Different values per build
- Cannot change at runtime
- Bundled into client code
Runtime Variables (Server)
// Accessed at runtime
const dbHost = process.env.DB_HOST;
// Value from environment at runtime
Characteristics:
- Accessed at runtime
- Can change without rebuild
- Server-only access
- Not bundled
Common Patterns
API Configuration
# .env
VITE_API_URL=http://localhost:3000
VITE_API_TIMEOUT=5000
// Client code
const apiUrl = import.meta.env.VITE_API_URL;
const timeout = Number(import.meta.env.VITE_API_TIMEOUT) || 5000;
fetch(`${apiUrl}/data`, { signal: AbortSignal.timeout(timeout) });
Database Configuration
# .env (server-only)
DATABASE_URL=postgresql://user:pass@localhost:5432/db
REDIS_URL=redis://localhost:6379
// Server code
"use server";
export async function connectDB() {
const db = new Database(process.env.DATABASE_URL);
const redis = new Redis(process.env.REDIS_URL);
return { db, redis };
}
Feature Flags
# .env
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_DEBUG=false
// Client code
const enableAnalytics = import.meta.env.VITE_ENABLE_ANALYTICS === "true";
const enableDebug = import.meta.env.VITE_ENABLE_DEBUG === "true";
if (enableAnalytics) {
initAnalytics();
}
if (enableDebug) {
console.log("Debug mode enabled");
}
Environment-Specific Config
// config.ts
export const config = {
apiUrl: import.meta.env.VITE_API_URL || "http://localhost:3000",
isDev: import.meta.env.DEV,
isProd: import.meta.env.PROD,
mode: import.meta.env.MODE,
};
TypeScript Setup
Complete env.d.ts example:
/// <reference types="vite/client" />
interface ImportMetaEnv {
// Public variables (VITE_ prefix)
readonly VITE_API_URL: string;
readonly VITE_APP_NAME: string;
readonly VITE_ENABLE_ANALYTICS: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
declare namespace NodeJS {
interface ProcessEnv {
// Server-only variables (no VITE_ prefix)
readonly DATABASE_URL: string;
readonly DB_PASSWORD: string;
readonly API_SECRET_KEY: string;
readonly REDIS_URL: string;
}
}
Vite Built-in Variables
Vite provides built-in environment variables:
import.meta.env.MODE // "development" | "production"
import.meta.env.DEV // true in dev, false in prod
import.meta.env.PROD // false in dev, true in prod
import.meta.env.SSR // true when running in SSR
import.meta.env.BASE_URL // Base public path
Deployment Considerations
Platform-Specific Setup
Different platforms handle environment variables differently:
Vercel:
- Set in dashboard or
vercel.json - Automatically available as
process.env
Netlify:
- Set in dashboard or
netlify.toml - Available as
process.env
Node.js:
- Use
.envfiles with dotenv - Or set in system environment
Build-Time vs Runtime
// Build-time (VITE_*)
const apiUrl = import.meta.env.VITE_API_URL;
// Set before build, bundled into code
// Runtime (server)
const dbUrl = process.env.DATABASE_URL;
// Set at runtime, not bundled
Best Practices
-
Always prefix public variables with
VITE_:- Prevents accidental exposure
- Clear distinction between public/private
-
Never use
VITE_for secrets:- Secrets should be server-only
- Use
process.envwithout prefix
-
Use TypeScript for type safety:
- Define in
env.d.ts - Get autocomplete and type checking
- Define in
-
Use
.env.localfor local overrides:- Not committed to git
- Overrides other env files
-
Document required variables:
- List in README
- Provide
.env.exampletemplate
-
Validate environment variables:
tsxconst requiredEnv = { apiUrl: import.meta.env.VITE_API_URL, }; if (!requiredEnv.apiUrl) { throw new Error("VITE_API_URL is required"); }
Summary
- Public variables:
VITE_prefix,import.meta.env, client-accessible - Private variables: No prefix,
process.env, server-only - Type safety: Define in
env.d.ts - Security: Never expose secrets with
VITE_prefix - Build-time: VITE_ variables replaced during build
- Runtime: Server variables accessed at runtime
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?