Multi-environment data source selector with feature flags and production safety. Perfect for testing and debugging across multiple environments simultaneously.
Environment Selector: Lets you choose which app environment to use (e.g., development, staging, production). Useful for testing how your app behaves in different deployment contexts.
Data Source Selector: Lets you choose where your app gets its data (e.g., mock data, local database, remote API). Useful for switching between test data and real data sources.
This package combines both!
- Select environments (dev, UAT, prod) and data sources (mock, local, API) in one UI.
- Multi-select and merge data from several sources/environments for advanced testing and debugging.
This flexibility makes it a powerful tool for development, QA, and debugging.
β¨ Multi-Select - Select and merge data from multiple environments simultaneously
π Production Safe - Automatically hidden in production deployments
π― Feature Flag - Company-only internal tool with "Internal" badge
πΎ Persistent - Selection saved to localStorage
π Zero Config - Works out of the box in development
β‘ Parallel Fetching - Fetch from multiple sources in parallel
npm install @interzept/interzept-environment-selector
# or
pnpm add @interzept/interzept-environment-selector
# or
yarn add @interzept/interzept-environment-selectornpm install @interzept/interzept-environment-selector --registry=https://npm.pkg.github.com// app/layout.tsx
import { DataSourceProvider } from '@interzept/interzept-environment-selector'
export default function RootLayout({ children }) {
return (
<html>
<body>
<DataSourceProvider>
{children}
</DataSourceProvider>
</body>
</html>
)
}You can create thin wrapper files in your app or in this package to customize, feature-flag, or style the exports from @interzept/interzept-environment-selector. Wrappers help keep your import paths stable and allow you to add app-specific logic.
Example: Custom Wrapper for DataSourceToggle
// src/data-source-toggle-wrapper.tsx
// Add feature flags, custom props, or styling here if needed
export { DataSourceToggle } from '@interzept/interzept-environment-selector'Why use wrappers?
- Add feature flags or environment checks
- Apply custom styling or theming
- Set default props or behaviors
- Add logging, analytics, or permission checks
- Keep your app's import paths stable
Other developers can import from your wrapper instead of the package directly if they need custom logic. For most use cases, importing directly from the package is fine.
Choose the version that fits your project:
Option A: With Tailwind CSS
// components/sidebar.tsx
import { DataSourceToggle } from '@interzept/interzept-environment-selector'
export function Sidebar() {
return (
<nav>
<DataSourceToggle />
</nav>
)
}Then configure Tailwind to scan the package:
// tailwind.config.js
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./node_modules/@interzept/interzept-environment-selector/dist/**/*.{js,mjs}'
],
}Option B: Without Tailwind (Plain CSS)
// components/sidebar.tsx
import { DataSourceToggleUnstyled } from '@interzept/interzept-environment-selector/unstyled'
import '@interzept/interzept-environment-selector/styles.css'
export function Sidebar() {
return (
<nav>
<DataSourceToggleUnstyled />
</nav>
)
}No configuration needed! Works in any React project.
// components/my-component.tsx
import { useDataSource, useMockData } from '@interzept/interzept-environment-selector'
export function MyComponent() {
const isMockMode = useMockData()
const { getApiBaseUrls } = useDataSource()
useEffect(() => {
if (isMockMode) {
setData(MOCK_DATA)
return
}
// Fetch from all selected sources in parallel
const urls = getApiBaseUrls()
const results = await Promise.allSettled(
urls.map(url => fetch(`${url}/api/endpoint?tenantId=${tenantId}`))
)
// Merge all successful results
const allData = []
results.forEach((result) => {
if (result.status === 'fulfilled') {
allData.push(...result.value.data)
}
})
setData(allData)
}, [isMockMode, getApiBaseUrls])
return <div>{/* Your UI */}</div>
}Create a .env.local file:
# Data source configuration
NEXT_PUBLIC_DATA_SOURCE=local
# Feature flag (optional - enabled by default in dev)
# NEXT_PUBLIC_ENABLE_DATA_SOURCE_TOGGLE=false
# Production safety (optional - recommended)
NEXT_PUBLIC_PRODUCTION_READ_ONLY=true
# Environment-specific API URLs
NEXT_PUBLIC_DEV_API_URL=https://dev-api.yourapp.com
NEXT_PUBLIC_UAT_API_URL=https://uat-api.yourapp.com
NEXT_PUBLIC_PROD_API_URL=https://api.yourapp.com| Source | Description | Icon | Use Case |
|---|---|---|---|
| Mock | Static test data | π§ͺ | UI development without backend |
| Local | Local Supabase/DB | πΎ | Feature development |
| Dev | Preview environment | π₯οΈ | Testing commits/PRs |
| UAT | Main branch | π’ | Pre-production testing |
| Production | Release branch | π | Live data (read-only by default) |
Wraps your app to provide data source context.
<DataSourceProvider>
{children}
</DataSourceProvider>Access data source state and methods.
const {
selectedSources, // DataSourceMode[] - Currently selected sources
toggleSource, // (mode: DataSourceMode) => void - Toggle a source
setSelectedSources, // (modes: DataSourceMode[]) => void - Set sources
useMockData, // () => boolean - Is mock mode active?
getApiBaseUrls, // () => string[] - Get all selected API URLs
primarySource, // DataSourceMode - First selected source
isProductionReadOnly, // boolean - Is production read-only?
canShowToggle, // boolean - Should toggle be visible?
} = useDataSource()Shorthand to check if mock mode is active.
const isMockMode = useMockData()Check if any real API source is selected.
const hasApiData = useApiData()UI component for source selection. Choose based on your styling preference:
// Tailwind version (requires Tailwind CSS setup)
import { DataSourceToggle } from '@interzept/interzept-environment-selector'
<DataSourceToggle />
// Plain CSS version (works everywhere)
import { DataSourceToggleUnstyled } from '@interzept/interzept-environment-selector/unstyled'
import '@interzept/interzept-environment-selector/styles.css'
<DataSourceToggleUnstyled />Uses Tailwind utility classes. Requires:
- Tailwind CSS configured in your project
- Package path added to Tailwind content config
lucide-reactinstalled
Uses standalone CSS with class prefix dst-*. To customize:
/* Override in your own CSS file */
.dst-container {
margin-bottom: 2rem !important;
}
.dst-header {
color: #your-color !important;
}
.dst-item-button:hover {
background-color: #your-hover-color !important;
}Available CSS Classes:
.dst-container- Main wrapper.dst-header- Collapsible header button.dst-badge- "Internal" badge.dst-item-button- Each data source button.dst-icon-purple,.dst-icon-blue,.dst-icon-green,.dst-icon-amber,.dst-icon-red- Icon colors.dst-footer- Footer with selection count
| Feature | Tailwind (DataSourceToggle) |
Plain CSS (DataSourceToggleUnstyled) |
|---|---|---|
| Setup | Requires Tailwind config | Import CSS once |
| Customization | Tailwind classes or wrapper | CSS overrides with !important |
| Bundle Size | Smaller (utility classes) | Includes compiled CSS (~3KB) |
| Best For | Tailwind projects | Any React project |
The toggle automatically hides in production when:
NODE_ENV === 'production'ANDNEXT_PUBLIC_VERCEL_ENV === 'production'
| Environment | Toggle Visible? | Production Selectable? |
|---|---|---|
| Local dev | β Always | π No (if read-only enabled) |
| Vercel Preview | β Always | π No (if read-only enabled) |
| Vercel Production | β Never | β Never |
const API_URLS = {
local: process.env.NEXT_PUBLIC_LOCAL_URL || 'http://localhost:55321',
dev: process.env.NEXT_PUBLIC_DEV_API_URL || 'https://dev.api.com',
// ...
}async function fetchMultiSource(endpoint: string) {
const { getApiBaseUrls } = useDataSource()
const urls = getApiBaseUrls()
const results = await Promise.allSettled(
urls.map(baseUrl =>
fetch(`${baseUrl}${endpoint}`)
.then(res => res.json())
)
)
// Handle results
const allData = results
.filter(r => r.status === 'fulfilled')
.flatMap(r => r.value.data)
return allData
}const { canShowToggle } = useDataSource()
return (
<nav>
{canShowToggle && <DataSourceToggle />}
</nav>
)Full TypeScript support included:
import type { DataSourceMode } from '@interzept/interzept-environment-selector'
type DataSourceMode = 'mock' | 'local' | 'dev' | 'uat' | 'production'Contributions welcome!
MIT
Built with β€οΈ for developers who need to test across multiple environments simultaneously.
Check out other Interzept projects:
- Interzept Browser Extension - Browser extension for enhanced development workflows
Need help? Open an issue on GitHub