@mariozechner/create-app
v1.0.11
Published
Project scaffolding for TypeScript applications and libraries
Downloads
42
Readme
Create App
CLI for creating deployable web applications with Docker, Caddy, and modern tooling.
Why This Exists
Self-hosting web applications shouldn't require complex infrastructure. This CLI creates apps that deploy to a single server with automatic SSL and dev/prod parity - simple, reliable hosting on your own or rented hardware.
Perfect for:
- Personal projects - blogs, portfolios, side projects
- Small businesses - company websites, internal tools
- Prototypes - MVPs that need real deployment
- Learning - because it's fun to run your own infra stack
Not suitable for:
- High-scale applications (use Kubernetes/cloud platforms)
- Multi-region deployments (single server architecture)
- Complex microservices (better served by orchestration platforms)
Quick Start
Interactive Setup
# Create a new app (prompts for template and configuration)
npx @mariozechner/create-app my-app
cd my-app
# Start development server
./run.sh dev
# Deploy to your server (see Server section below)
./run.sh deployCLI Arguments (No Prompts)
# Create with all options specified
npx @mariozechner/create-app my-app \
--template spa-api \
--domain myapp.com \
--server myserver.hetzner.de \
--serverDir /home/username
# Quick static site
npx @mariozechner/create-app my-blog --template static --domain blog.example.com
# See all options
npx @mariozechner/create-app --helpTemplates
Available Templates
Static
- Description: Static file server with modern frontend tooling
- Features:
- Tailwind CSS 4 with live reload
- TypeScript support
- Automated testing setup
- Optimized production builds
- Use for: Landing pages, documentation sites, blogs, portfolios
SPA + API
- Description: Single Page Application with backend API
- Inherits: All features from the Static template
- Additional Features:
- Express.js backend API
- Frontend/backend code sharing
- API proxy in development
- Separate frontend/backend builds
- Use for: Web apps, internal tools, data-driven applications
Web Library
- Description: TypeScript library for the browser
- Features:
- ESM output with source maps
- TypeScript declarations
- Hot-reload development server with @mariozechner/hotserve
- Prettier formatting + Biome linting
- Publishing script included
- Use for: Browser libraries, web components, frontend utilities
Node Library
- Description: TypeScript library for Node.js with CLI support
- Features:
- ESM output with TypeScript declarations
- CLI executable support
- Prettier formatting + Biome linting
- Publishing script included
- Use for: Node.js libraries, CLI tools, backend utilities
Prerequisites
Server Setup
Your production server needs Docker, Caddy, and proper configuration. See SERVER.md for complete setup instructions.
DNS Configuration
Point your domain to the server:
A yourdomain.com -> server-ip
A *.yourdomain.com -> server-ip (for subdomains)Usage
CLI Options
| Option | Short | Description | Example |
|--------|-------|-------------|---------|
| --template | -t | Template to use | --template spa-api |
| --domain | | Domain for the app | --domain myapp.com |
| --server | | Production server hostname | --server myserver.com |
| --serverDir | | Server directory path | --serverDir /home/username |
| --frontendPort | | Frontend development port | --frontendPort 3000 |
| --apiPort | | API development port | --apiPort 8000 |
| --help | -h | Show help message | --help |
Available templates: static, spa-api, web-library, node-library
Template-Specific Instructions
After creating a project, check the generated README.md for detailed instructions specific to your template.
npx @mariozechner/create-app my-blog
cd my-blog
cat README.md # Template-specific instructionsDevelopment
Working on the CLI
To work on this CLI tool itself:
git clone https://github.com/badlogic/create-app
cd create-app
npm install
npx tsx src/cli.ts test-appTemplate System
The template system supports inheritance and file transformations, making it easy to create and maintain templates.
Template Structure
Each template is a directory in templates/ containing:
template.json- Template metadata and configuration- Template files and directories
- Special filename prefixes for transformations:
+filename- File will be merged with inherited file (JSON/YAML only)-filename- Marks a file/directory for deletion from inherited template- Regular files - Replace inherited files or create new ones
Creating a New Template
- Create a new directory in
templates/:
mkdir templates/my-template- Add
template.json:
{
"name": "My Template",
"description": "Description of what this template creates",
"prompts": [
{
"name": "domain",
"type": "text",
"message": "Domain (e.g. myapp.com)"
}
]
}- Add your template files with proper structure:
templates/my-template/
├── template.json
├── package.json
├── src/
│ └── index.ts
└── infra/
├── Caddyfile
└── docker-compose.ymlTemplate Inheritance
Templates can inherit from other templates using the inherits field:
{
"name": "Extended Template",
"description": "Builds on the static template",
"inherits": ["static"],
"prompts": [...]
}Inheritance rules:
- Files from parent templates are copied first
- Child template files override parent files with the same path
- Files prefixed with
+are merged with parent files (JSON/YAML only) - Files prefixed with
-delete the corresponding file from parent - Multiple inheritance is processed in order
Example: The spa-api template inherits from static and:
- Keeps all static template files (frontend build, testing, etc.)
- Adds
+package.jsonto merge additional dependencies - Adds
+docker-compose.ymlto extend Docker services - Adds new files like
src/backend/server.ts - Could use
-README.mdto remove the parent's README (if needed)
File Merging
Files prefixed with + are intelligently merged based on their type:
- JSON files (
+package.json): Deep merged with parent - YAML files (
+docker-compose.yml): Deep merged with special handling for arrays - Other files: Not supported for merging (warning shown)
Example +package.json in child template:
{
"scripts": {
"build:backend": "tsup"
},
"dependencies": {
"express": "^4.18.0"
}
}This will merge with the parent's package.json, adding new scripts and dependencies.
File Deletion
Files or directories prefixed with - mark items for deletion from the inherited template:
-README.md- Removes README.md from parent template-src/oldfeature/- Removes entire directory from parent template
This is useful when inheriting from a template but needing to remove specific files.
Variable Substitution
Template files can use variables that get replaced during project creation:
{{projectName}}- The project name{{domain}}- The domain from prompts{{server}}- The server hostname{{serverDir}}- The server directory- Any other prompt values
Best Practices
- Use inheritance to avoid duplication - build on existing templates
- Keep templates focused - each template should solve one use case well
- Document your template - include a README.md in the template
- Test thoroughly - ensure both dev and production modes work
- Follow conventions - match the structure and patterns of existing templates
Common Issues
Server setup required: Before deploying, your server needs Docker and Caddy configured. See SERVER.md for complete setup instructions.
Template-specific issues:
Check the README.md in your generated project for troubleshooting specific to your template type.
Publishing
The publish.sh script handles versioning, tagging, and publishing to npm:
# Patch release (1.0.0 -> 1.0.1)
./publish.sh
# Minor release (1.0.1 -> 1.1.0)
./publish.sh minor
# Major release (1.1.0 -> 2.0.0)
./publish.sh majorThe script will:
- Check for uncommitted changes
- Run checks (format, lint, type-check)
- Build the project
- Bump version in package.json
- Commit and tag the version
- Push to GitHub with tags
- Publish to npm
Contributing
Contributions are welcome! When adding new templates:
- Follow the template structure guidelines above
- Include comprehensive documentation
- Test both development and production workflows
- Consider if inheritance from existing templates makes sense
