Browse source code
A modern full-stack .NET 10.0 + Next.js 16 project template that combines the power of ServiceStack with Next.js static site generation and React 19. It provides a production-ready foundation for building scalable web applications with integrated authentication, database management, and background job processing.
npx create-net next-static MyProjectRun Server .NET Project (automatically starts both .NET and Next.js dev servers):
cd MyProject
dotnet watchDevelopment Mode:
- ASP.NET Core proxies requests to Next.js dev server (running on port 3000)
- Hot Module Replacement (HMR) support for instant UI updates
- WebSocket proxying for Next.js HMR functionality
Production Mode:
- Next.js app is statically exported to
/dist - Static files served directly from ASP.NET Core's
/wwwroot - No separate Node.js server required in production
- Next.js with static export capability
- Tailwind CSS 4.x - Utility-first styling with PostCSS
- TypeScript - Type-safe development
- Vitest - Modern testing framework
- ServiceStack React Components - Pre-built UI components
- Razor Pages - For Identity Auth UI (
/Identityroutes)
- ServiceStack 10.x - High-performance web services framework
- ASP.NET Core Identity - Complete authentication & authorization system
- Entity Framework Core - For Identity data management
- OrmLite - ServiceStack's fast, lightweight Typed ORM for application data
- SQLite - Default database (easily upgradable to PostgreSQL/SQL Server/MySQL)
- ASP.NET Core Identity integration with role-based access control
- Custom user sessions with additional claims
- Admin users feature for user management at
/admin-ui/users - Email confirmation workflow (configurable SMTP)
- Razor Pages for Identity UI (
/Identityroutes) - Credentials-based authentication
- Declarative API development with minimal code
- Complete Auth-protected CRUD operations (see Bookings example at
/bookings-auto) - Automatic audit trails (created/modified/deleted tracking)
- Built-in validation and authorization
- Type-safe TypeScript DTOs auto-generated from C# models
BackgroundsJobFeaturefor async task processing- Command pattern for job execution
- Email sending via background jobs
- Recurring job scheduling support
- Upgradable to
DatabaseJobsFeaturefor enterprise RDBMS
- Admin UI at
/admin-uifor App management - Health checks at
/upendpoint - Modular startup configuration pattern
- Code-first migrations with OrmLite
- Docker support with container publishing
- Kamal deployment configuration included
- Static asset caching with intelligent cache invalidation
- Clean URLs without
.htmlextensions - HTTPS redirection and HSTS
- Data protection with persistent keys
- Health monitoring
- Database developer page for EF Core errors
MyApp/ # Main ASP.NET Core host
├── Configure.*.cs # Modular startup configuration
├── Program.cs # Application entry point
└── wwwroot/ # Static files (production)
MyApp.Client/ # Next.js frontend application
├── app/ # Next.js App Router pages
├── components/ # React components
├── lib/ # Utilities and helpers
├── public/ # Static assets
├── dist/ # Build output (production)
└── styles/ # Tailwind CSS styles
MyApp.ServiceInterface/ # Service implementations
├── MyServices.cs # Example services
└── Data/ # EF Core DbContext
MyApp.ServiceModel/ # DTOs and service contracts
├── Bookings.cs # AutoQuery CRUD example
└── Hello.cs # Example service contract
MyApp.Tests/ # Integration and unit tests
config/ # Deployment configuration
└── deploy.yml # Kamal deployment settings
.github/ # GitHub Actions workflows
└── workflows/
├── build.yml # CI build and test
├── build-container.yml # Container image build
└── release.yml # Production deployment with Kamal
dotnet watchThis automatically starts both .NET and Next.js dev servers.
After modifying C# service models, regenerate TypeScript dtos.ts in MyApp or MyApp.Client with:
npm run dtosOrmLite and Entity Framework:
npm run migrateOrmLite (for application data):
Create migration classes in MyApp/Migrations/ following the pattern in Migration1000.cs.
Frontend:
cd MyApp.Client
npm run test # Run tests in watch mode
npm run test:ui # Run tests with UI
npm run test:run # Run tests onceBackend:
dotnet test- MyApp/appsettings.json - Application configuration
- MyApp.Client/next.config.mjs - Next.js configuration
- MyApp.Client/styles/index.css - Tailwind CSS configuration
- config/deploy.yml - Kamal deployment settings
Configure in appsettings.json or environment:
{
"ConnectionStrings": {
"DefaultConnection": "DataSource=App_Data/app.db;Cache=Shared"
},
"SmtpConfig": {
"Host": "smtp.example.com",
"Port": 587,
"FromEmail": "noreply@example.com",
"FromName": "MyApp"
},
"AppConfig": {
"BaseUrl": "https://myapp.example.com"
}
}Instead of polluting each GitHub Reposity with multiple App-specific GitHub Action Secrets, you can save all your secrets in a single APPSETTINGS_PATCH GitHub Action Secret to patch appsettings.json with environment-specific configuration using JSON Patch. E.g:
[
{
"op":"replace",
"path":"/ConnectionStrings/DefaultConnection",
"value":"Server=service-postgres;Port=5432;User Id=dbuser;Password=dbpass;Database=dbname;Pooling=true;"
},
{ "op":"add", "path":"/SmtpConfig", "value":{
"UserName": "SmptUser",
"Password": "SmptPass",
"Host": "email-smtp.us-east-1.amazonaws.com",
"Port": 587,
"From": "noreply@example.org",
"FromName": "MyApp",
"Bcc": "copy@example.org"
}
},
{ "op":"add", "path":"/Admins", "value": ["admin1@email.com","admin2@email.com"] },
{ "op":"add", "path":"/CorsFeature/allowOriginWhitelist/-", "value":"https://servicestack.net" }
]Enable email sending by uncommenting in Program.cs:
services.AddSingleton<IEmailSender<ApplicationUser>, EmailSender>();To switch from SQLite to PostgreSQL/SQL Server/MySQL:
- Install preferred RDBMS (ef-postgres, ef-mysql, ef-sqlserver), e.g:
npx add-in ef-postgres- Install
db-identityto use RDBMSDatabaseJobsFeaturefor background jobs andDbRequestLoggerfor Request Logs:
npx add-in db-identityThis project includes GitHub Actions for CI/CD with automatic Docker image builds and production deployment with Kamal. The /config/deploy.yml configuration is designed to be reusable across projects—it dynamically derives service names, image paths, and volume mounts from environment variables, so you only need to configure your server's IP and hostname using GitHub Action secrets.
*Required - App Specific:
The only secret needed to be configured per Repository.
| Variable | Example | Description |
|---|---|---|
KAMAL_DEPLOY_HOST |
example.org |
Hostname used for SSL certificate and Kamal proxy |
Required (Organization Secrets):
Other Required variables can be globally configured in your GitHub Organization or User secrets which will enable deploying all your Repositories to the same server.
| Variable | Example | Description |
|---|---|---|
KAMAL_DEPLOY_IP |
100.100.100.100 |
IP address of the server to deploy to |
SSH_PRIVATE_KEY |
ssh-rsa ... |
SSH private key to access the server |
LETSENCRYPT_EMAIL |
me@example.org |
Email for Let's Encrypt SSL certificate |
Optional:
| Variable | Example | Description |
|---|---|---|
SERVICESTACK_LICENSE |
... |
ServiceStack license key |
Inferred (from GitHub Action context):
These are inferred from the GitHub Action context and don't need to be configured.
| Variable | Source | Description |
|---|---|---|
GITHUB_REPOSITORY |
${{ github.repository }} |
e.g. acme/example.org - used for service name and image |
KAMAL_REGISTRY_USERNAME |
${{ github.actor }} |
GitHub username for container registry |
KAMAL_REGISTRY_PASSWORD |
${{ secrets.GITHUB_TOKEN }} |
GitHub token for container registry auth |
- Docker containerization with optimized .NET images
- SSL auto-certification via Let's Encrypt
- GitHub Container Registry integration
- Volume persistence for App_Data including any SQLite database
For Rapid Development simple TypeScript Data Models can be used to generate C# AutoQuery APIs and DB Migrations.
Create a new Table use init <Table>, e.g:
npx okai init TableThis will generate an empty MyApp.ServiceModel/<Table>.d.ts file along with stub AutoQuery APIs and DB Migration implementations.
After modifying the TypeScript Data Model to include the desired fields, re-run the okai tool to re-generate the AutoQuery APIs and DB Migrations:
npx okai Table.d.tsCommand can be run anywhere within your Solution
After you're happy with your Data Model you can run DB Migrations to run the DB Migration and create your RDBMS Table:
npm run migrateIf you want to make further changes to your Data Model, you can re-run the okai tool to update the AutoQuery APIs and DB Migrations, then run the rerun:last npm script to drop and re-run the last migration:
npm run rerun:lastIf you changed your mind and want to get rid of the RDBMS Table you can revert the last migration:
npm run revert:lastWhich will drop the table and then you can get rid of the AutoQuery APIs, DB Migrations and TypeScript Data model with:
npx okai rm Transaction.d.ts- SaaS applications requiring authentication
- Admin dashboards with CRUD operations
- Content-driven sites with dynamic APIs
- Applications needing background job processing
- Projects requiring both SSG benefits and API capabilities
- Teams wanting type-safety across full stack
