Open-source alternative to Vercel's Password Protection feature
npm install stagingFree and open-source alternative to Vercel's Password Protection and Netlify's Password Protection for Non-Production Deploys - protect your staging environments without enterprise or pro plan requirements.





Staging provides a simple, secure way to password protect your staging environments - for free. While Vercel's Password Protection requires an Enterprise plan and Netlify's protection requires a Pro plan, staging offers the same core functionality as an open-source solution. It works seamlessly with Express, Next.js and Nuxt.js applications, offering a modern, responsive login interface.
* 🆓 Free and Open Source: No enterprise or pro plans required
* 🔄 Environment-based Protection: Easily protect preview/staging environments using platform environment variables (VERCEL_ENV, NETLIFY_ENV, or your own)
* 🌐 Framework Agnostic: Works with Next.js, Nuxt.js, and Express.js out of the box
* ⚡️ Edge Compatible: Optimized for Edge Runtime in Next.js
* 🛠️ Simple Setup: Get running in minutes with just a few lines of code
* 💰 Cost Effective: Save hundreds of dollars per month compared to platform-specific solutions
https://github.com/user-attachments/assets/c9369415-bc26-41e3-88c8-2de7a72e14c5
Try out our demo sites (password: demo):
* 🚀 Next.js Demo: staging-next.vercel.app
* ⚡️ Nuxt.js Demo: staging-nuxt.vercel.app
* 🔐 Simple password protection
* 🎨 Beautiful, modern login page with light/dark mode
* ⚡️ Works with Express, Next.js and Nuxt.js
* 🎯 Flexible route protection with regex support
* 🔄 Session support for better UX
* 🌍 Environment variables configuration
* 🛡️ Secure by default
* 📱 Mobile-friendly design
``typescript
// Next.js example (middleware.ts)
import staging from 'staging-next';
export const middleware = staging({
// Only enable password protection on preview deployments
enabled: process.env.VERCEL_ENV === 'preview',
password: process.env.STAGING_PASSWORD,
siteName: "Preview Site"
});
`
`typescript
// Next.js example (middleware.ts)
import staging from 'staging-next';
export const middleware = staging({
// Protect deploy previews and branch deploys
enabled: ['deploy-preview', 'branch-deploy'].includes(process.env.CONTEXT),
password: process.env.STAGING_PASSWORD,
siteName: "Preview Site"
});
`
You can protect specific environments based on your needs:
`typescript
const isProtectedEnvironment =
process.env.VERCEL_ENV === 'preview' || // Vercel preview deployments
process.env.CONTEXT === 'deploy-preview' || // Netlify deploy previews
process.env.NODE_ENV === 'staging' || // Staging environment
process.env.PROTECT_ENV === 'true'; // Custom protection flag
export const middleware = staging({
enabled: isProtectedEnvironment,
password: process.env.STAGING_PASSWORD
});
`
Each framework has its own package with specific optimizations and implementations:
* Express.js: staging-express
* Next.js: staging-next
* Nuxt.js: staging-nuxt
Choose and install the package for your framework:
`bashFor Express.js
npm install staging-expressor
yarn add staging-expressor
pnpm add staging-express
Quick Start
$3
`typescript
import express from 'express';
import staging from 'staging-express';
import cookieParser from 'cookie-parser';const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(staging({
password: process.env.STAGING_PASSWORD
}));
`For more Express.js specific features, check out the Express.js docs.
$3
`typescript
// middleware.ts
import staging from 'staging-next';export const middleware = staging({
password: process.env.STAGING_PASSWORD
});
`For Edge Runtime optimizations and Next.js specific features, check out the Next.js docs.
$3
`typescript
// server/middleware/staging.ts
import staging from "staging-nuxt";export default staging({
password: process.env.STAGING_PASSWORD
});
`For Nuxt-specific features and H3 integration, check out the Nuxt.js docs.
Configuration
$3
All frameworks support these base options:
`typescript
interface StagingOptions {
/* Whether the protection should be enabled. Default: true. Can be set via STAGING_ENABLED env var /
enabled?: boolean;
/* The password required to access protected routes. Can be set via STAGING_PASSWORD env var /
password?: string; /* Duration in milliseconds for how long the auth cookie remains valid. Default: 7 days. Can be set via STAGING_COOKIE_MAX_AGE env var (in days) /
cookieMaxAge?: number;
/* Secret used to sign the JWT token. Default: randomly generated. Can be set via STAGING_JWT_SECRET env var /
jwtSecret?: string;
/* Path for the login endpoint. Default: '/protected'. Can be set via STAGING_LOGIN_PATH env var /
loginPath?: string;
/* Name displayed on the login page. Default: 'Protected Page'. Can be set via STAGING_SITE_NAME env var /
siteName?: string;
/* Routes that should be protected. Default: all routes except loginPath. Can be set via STAGING_PROTECTED_ROUTES env var as comma-separated paths /
protectedRoutes?: string[];
/* Routes that should never be protected. Default: []. Can be set via STAGING_PUBLIC_ROUTES env var as comma-separated paths /
publicRoutes?: string[];
/* URL to redirect to after successful login. Default: the original requested URL. Can be set via STAGING_REDIRECT_URL env var /
redirectUrl?: string;
}
`Each framework may provide additional options. See their respective documentation for details.
$3
All options can be configured via environment variables:
To generate secure secrets for your environment, you can use:
`bash
Generate a secure JWT secret
openssl rand -base64 32
or
node -e "console.log(crypto.randomBytes(32).toString('base64'))"
`Then set your environment variables:
`env
Required
STAGING_PASSWORD=your-passwordOptional
STAGING_ENABLED=true
STAGING_JWT_SECRET=your-jwt-secret
STAGING_COOKIE_MAX_AGE=7 # days
STAGING_LOGIN_PATH=/protected
STAGING_SITE_NAME="Protected Page"
STAGING_PROTECTED_ROUTES=/admin/,/dashboard/
STAGING_PUBLIC_ROUTES=/api/public/,/static/
STAGING_REDIRECT_URL=/
`$3
You can use regex patterns to protect or expose routes:
`typescript
{
// Protect specific paths
protectedRoutes: [
'^/admin(/.)?$', // Protect /admin/
'^/dashboard(/.)?$' // Protect /dashboard/
], // Make specific paths public
publicRoutes: [
'^/(_next|static|images)(/.*)?$', // Public assets
'^/api/public(/.*)?$' // Public API routes
]
}
``The middleware:
* Uses secure httpOnly cookies
* Implements JWT for token validation
* Enables secure cookies in production
* Implements sameSite cookie policy
* Generates random JWT secrets by default
Full examples for each framework are available in the repository:
* Express.js Example
* Next.js Example
* Nuxt.js Example
Each framework implementation has its own optimizations and features:
* Express.js (docs)
* Session support
* Express middleware integration
* Node.js optimized
* Next.js (docs)
* Edge Runtime compatible
* Next.js middleware
* Cookie-based session handling
* Nuxt.js (docs)
* H3 integration
* Nuxt-specific route handling
* Cookie-based session handling
Contributions are welcome! Please see our Contributing Guide for more details.
*
Built with ❤️ by Antoine Kingue