Skip to Content

Real-World Examples

Practical examples and patterns for common use cases.

Basic Examples

Minimal Setup

The simplest possible configuration:

api/config.py
from django_cfg import DjangoConfig, NextJsAdminConfig config = DjangoConfig( project_name="Simple Blog", secret_key="your-secret-key", nextjs_admin=NextJsAdminConfig( project_path="../admin-frontend", ), )

That’s it! Everything else uses smart defaults.

Custom Port for Development

If port 3001 is already in use:

api/config.py
config = DjangoConfig( project_name="My App", nextjs_admin=NextJsAdminConfig( project_path="../admin-frontend", dev_url="http://localhost:3002", # Custom dev port ), )

Update Next.js dev command:

package.json
{ "scripts": { "dev": "next dev -p 3002" } }

Custom Production URL

For a branded admin URL:

api/config.py
config = DjangoConfig( project_name="Analytics Platform", nextjs_admin=NextJsAdminConfig( project_path="../analytics-ui", static_url="/analytics/", tab_title="Analytics Dashboard", ), )

Access at: https://yourdomain.com/analytics/

Advanced Examples

Multi-Environment Configuration

Different settings for dev, staging, and production:

api/config.py
import os ENV = os.getenv("ENV_MODE", "development") # Base configuration config = DjangoConfig( project_name="Multi-Env App", env_mode=ENV, ) # Environment-specific Next.js config if ENV == "development": config.nextjs_admin = NextJsAdminConfig( project_path="../admin-frontend", dev_url="http://localhost:3001", ) elif ENV == "staging": config.nextjs_admin = NextJsAdminConfig( project_path="/app/admin-frontend", static_url="/staging-admin/", ) else: # production config.nextjs_admin = NextJsAdminConfig( project_path="/app/admin-frontend", static_url="/admin/", )

Custom Next.js Structure

If your Next.js project doesn’t follow the default structure:

api/config.py
config = DjangoConfig( project_name="Custom Structure", nextjs_admin=NextJsAdminConfig( project_path="../my-admin-app", api_output_path="src/lib/api/generated", # Custom API path static_output_path="dist", # Custom build output ), )

This assumes your Next.js project looks like:

my-admin-app/ ├── src/ │ └── lib/ │ └── api/ │ └── generated/ # API clients here ├── dist/ # Build output here └── package.json

API Authentication in Next.js

Using generated API clients with authentication:

src/lib/api-client.ts
import { ProfilesClient } from '@/api/generated/profiles/client'; import { TradingClient } from '@/api/generated/trading/client'; // Get JWT token from localStorage (injected by Django) function getAuthToken(): string | null { if (typeof window === 'undefined') return null; return localStorage.getItem('auth_token'); } // Create authenticated API client export function createProfilesClient() { const token = getAuthToken(); return new ProfilesClient({ baseURL: '/api', headers: { 'Authorization': token ? `Bearer ${token}` : '', 'Content-Type': 'application/json', }, }); } export function createTradingClient() { const token = getAuthToken(); return new TradingClient({ baseURL: '/api', headers: { 'Authorization': token ? `Bearer ${token}` : '', }, }); }

Usage in components:

src/components/Dashboard.tsx
import { useEffect, useState } from 'react'; import { createProfilesClient } from '@/lib/api-client'; import { Profile } from '@/api/generated/profiles/types'; export default function Dashboard() { const [profile, setProfile] = useState<Profile | null>(null); const [loading, setLoading] = useState(true); useEffect(() => { async function loadProfile() { try { const client = createProfilesClient(); const data = await client.getProfile(); setProfile(data); } catch (error) { console.error('Failed to load profile:', error); } finally { setLoading(false); } } loadProfile(); }, []); if (loading) return <div>Loading...</div>; if (!profile) return <div>Failed to load profile</div>; return ( <div> <h1>Welcome, {profile.name}</h1> <p>Email: {profile.email}</p> </div> ); }

Token Refresh Hook

Automatically refresh expired JWT tokens:

src/hooks/useAuth.ts
import { useEffect, useState } from 'react'; interface AuthTokens { access: string | null; refresh: string | null; } export function useAuth() { const [tokens, setTokens] = useState<AuthTokens>({ access: null, refresh: null, }); useEffect(() => { // Read tokens from localStorage const access = localStorage.getItem('auth_token'); const refresh = localStorage.getItem('refresh_token'); setTokens({ access, refresh }); }, []); const refreshToken = async () => { if (!tokens.refresh) return false; try { const response = await fetch('/api/token/refresh/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh: tokens.refresh }), }); if (response.ok) { const data = await response.json(); localStorage.setItem('auth_token', data.access); setTokens({ ...tokens, access: data.access }); return true; } } catch (error) { console.error('Token refresh failed:', error); } return false; }; return { tokens, refreshToken }; }

Usage:

src/lib/api-client.ts
import { useAuth } from '@/hooks/useAuth'; export function useApiClient() { const { tokens, refreshToken } = useAuth(); const fetchWithAuth = async (url: string, options: RequestInit = {}) => { const headers = { ...options.headers, 'Authorization': `Bearer ${tokens.access}`, }; let response = await fetch(url, { ...options, headers }); // If 401, try to refresh token if (response.status === 401) { const refreshed = await refreshToken(); if (refreshed) { // Retry with new token headers.Authorization = `Bearer ${localStorage.getItem('auth_token')}`; response = await fetch(url, { ...options, headers }); } } return response; }; return { fetchWithAuth }; }

Real-World Use Cases

E-Commerce Analytics Dashboard

api/config.py
config = DjangoConfig( project_name="E-Commerce Platform", nextjs_admin=NextJsAdminConfig( project_path="../analytics-dashboard", static_url="/analytics/", tab_title="Analytics", iframe_route="/dashboard", ), project_apps=[ "apps.products", "apps.orders", "apps.analytics", ], )

Next.js dashboard with real-time charts:

apps/analytics-dashboard/src/pages/dashboard/index.tsx
import { useEffect, useState } from 'react'; import { Line, Bar } from 'react-chartjs-2'; import { createAnalyticsClient } from '@/lib/api-client'; export default function AnalyticsDashboard() { const [metrics, setMetrics] = useState(null); useEffect(() => { const client = createAnalyticsClient(); // Fetch initial data client.getDashboardMetrics().then(setMetrics); // Poll for updates every 30 seconds const interval = setInterval(() => { client.getDashboardMetrics().then(setMetrics); }, 30000); return () => clearInterval(interval); }, []); return ( <div className="grid grid-cols-2 gap-4"> <div className="card"> <h2>Sales Over Time</h2> <Line data={metrics?.salesData} /> </div> <div className="card"> <h2>Top Products</h2> <Bar data={metrics?.productsData} /> </div> </div> ); }

Multi-Tenant SaaS Admin

Different admin interfaces per tenant:

api/config.py
config = DjangoConfig( project_name="Multi-Tenant SaaS", nextjs_admin=NextJsAdminConfig( project_path="../tenant-admin", static_url="/tenant-admin/", tab_title="Tenant Dashboard", ), )

Next.js with tenant context:

src/contexts/TenantContext.tsx
import { createContext, useContext, useEffect, useState } from 'react'; interface Tenant { id: string; name: string; subdomain: string; } const TenantContext = createContext<Tenant | null>(null); export function TenantProvider({ children }) { const [tenant, setTenant] = useState<Tenant | null>(null); useEffect(() => { // Extract tenant from subdomain or API const subdomain = window.location.hostname.split('.')[0]; fetch(`/api/tenants/?subdomain=${subdomain}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('auth_token')}`, }, }) .then(res => res.json()) .then(setTenant); }, []); return ( <TenantContext.Provider value={tenant}> {children} </TenantContext.Provider> ); } export const useTenant = () => useContext(TenantContext);

IoT Device Management

Real-time device monitoring dashboard:

api/config.py
config = DjangoConfig( project_name="IoT Platform", nextjs_admin=NextJsAdminConfig( project_path="../device-dashboard", static_url="/devices/", tab_title="Device Monitor", ), # Enable Centrifugo for WebSocket centrifugo=DjangoCfgCentrifugoConfig( enabled=True, api_url="http://centrifugo:8000", ), )

Next.js with real-time updates via Centrifugo:

src/hooks/useDeviceStatus.ts
import { useEffect, useState } from 'react'; import Centrifuge from 'centrifuge'; interface Device { id: string; name: string; status: 'online' | 'offline'; lastSeen: string; } export function useDeviceStatus(deviceId: string) { const [device, setDevice] = useState<Device | null>(null); const [centrifuge, setCentrifuge] = useState<Centrifuge | null>(null); useEffect(() => { // Connect to Centrifugo const token = localStorage.getItem('auth_token'); const client = new Centrifuge('ws://localhost:8000/connection/websocket', { token, }); // Subscribe to device channel const sub = client.subscribe(`device:${deviceId}`, (ctx) => { setDevice(ctx.data); }); client.connect(); setCentrifuge(client); return () => { sub.unsubscribe(); client.disconnect(); }; }, [deviceId]); return { device, centrifuge }; }

Financial Trading Dashboard

Complex data visualization with real-time updates:

api/config.py
config = DjangoConfig( project_name="Trading Platform", nextjs_admin=NextJsAdminConfig( project_path="../trading-dashboard", static_url="/trading/", tab_title="Trading Desk", iframe_route="/desk", ), )

Next.js with TradingView charts:

src/components/TradingChart.tsx
import { useEffect, useRef } from 'react'; import { createTradingClient } from '@/lib/api-client'; export default function TradingChart({ symbol }: { symbol: string }) { const chartRef = useRef<HTMLDivElement>(null); useEffect(() => { const client = createTradingClient(); // Fetch historical data client.getHistoricalData(symbol).then((data) => { // Initialize TradingView chart const chart = new TradingView.widget({ container: chartRef.current!, symbol, interval: '1', datafeed: { // Custom datafeed using Django API getBars: async (symbolInfo, resolution, from, to) => { const bars = await client.getBars(symbol, from, to); return bars; }, }, }); }); }, [symbol]); return <div ref={chartRef} className="h-full w-full" />; }

Integration Patterns

API Response Caching

Cache API responses for better performance:

src/lib/cache.ts
const cache = new Map<string, { data: any; timestamp: number }>(); export async function cachedFetch<T>( key: string, fetcher: () => Promise<T>, ttl: number = 60000 // 1 minute default ): Promise<T> { const now = Date.now(); const cached = cache.get(key); if (cached && (now - cached.timestamp) < ttl) { return cached.data; } const data = await fetcher(); cache.set(key, { data, timestamp: now }); return data; }

Usage:

import { cachedFetch } from '@/lib/cache'; import { createProfilesClient } from '@/lib/api-client'; const profile = await cachedFetch( 'profile', () => createProfilesClient().getProfile(), 300000 // Cache for 5 minutes );

Optimistic Updates

Update UI immediately, sync with server later:

src/hooks/useOptimisticUpdate.ts
import { useState } from 'react'; export function useOptimisticUpdate<T>( initialData: T, updateFn: (data: T) => Promise<T> ) { const [data, setData] = useState<T>(initialData); const [isUpdating, setIsUpdating] = useState(false); const update = async (newData: Partial<T>) => { // Optimistic update setData((prev) => ({ ...prev, ...newData })); setIsUpdating(true); try { // Sync with server const updated = await updateFn({ ...data, ...newData }); setData(updated); } catch (error) { // Rollback on error setData(initialData); throw error; } finally { setIsUpdating(false); } }; return { data, update, isUpdating }; }

Next Steps

Need More Examples?

Check out our example repository  for complete working examples.