Quick Start
Quick Start
Get a Mithril app running in a few minutes.
1. Install the CLI#
curl -fsSL https://raw.githubusercontent.com/mithril-framework/mithril/main/install.sh | sh
2. Create a Project#
mithril new hello-mithril
cd hello-mithril
mithril install
mithril new copies env.example to .env and sets APP_NAME to your project name. The Go module defaults to github.com/your-user/project-name when GitHub CLI (gh) or git config github.user is available; otherwise the folder name is used. A tip is printed after scaffold when the module path is not under github.com/. Override with -module:
mithril new -module github.com/acme/api my-api
3. Start PostgreSQL#
make dc-up-postgres
mithril migrate-up
Create a login user — pick one:
# Fastest for local dev (demo credentials)
mithril seed
# Interactive superuser (TTY required for password)
mithril createsuperuser
# Non-interactive superuser (CI / scripts)
mithril createsuperuser --email admin@example.com --password 'your-secure-password'
After mithril seed, log in with user@example.com / password.
The Docker Postgres service uses trust auth and database mithril_rev — matching the defaults in .env.
4. Run the Server#
mithril run-dev # live reload with Air
# or: mithril run
If Postgres is not running, the app still starts in development with a warning (/, /health, /docs work). Set APP_ENV=production to require a working database.
5. Visit Your App#
| URL | Description |
|---|---|
| http://localhost:4000 | API root |
| http://localhost:4000/docs | Swagger UI |
| http://localhost:4000/health | Health check |
| http://localhost:4000/monitor | System monitor |
| http://localhost:4000/admin | Admin panel (after mithril admin-enable + restart) |
| http://localhost:5050 | Embedded DBMS (after mithril dbms-enable && mithril dbms) |
| http://localhost:5051 | pgAdmin (when make dc-up-pgadmin) |
Project Structure#
hello-mithril/
├── main.go # Fiber app bootstrap
├── routes/ # register.go, auth, CRUD, admin
├── internal/ # auth, acl, admin, crud handlers
├── database/
│ ├── models/ # User, Blog, ACL structs
│ ├── repositories/ # pgx data access
│ └── migrations/ # goose SQL files
├── cmd/ # mithril, crud, acl, seed, backup, …
├── pkg/utils/ # hash, encrypt, validation helpers
├── public/admin/ # Admin SPA
├── infrastructure/ # Docker compose, K8s
├── Makefile
└── mithril # delegates to make
Your First API Endpoint#
Add a route in routes/web.go or create routes/hello.go:
package routes
import "github.com/gofiber/fiber/v3"
func SetupHelloRoutes(app *fiber.App) {
app.Get("/api/hello", func(c fiber.Ctx) error {
return c.JSON(fiber.Map{"message": "Hello from Mithril!"})
})
}
Register it in routes/register.go inside RegisterAll:
SetupHelloRoutes(app)
Test:
curl http://localhost:4000/api/hello
Database Model & Migration#
1. Create a model
Add database/models/article.go:
package models
import (
"time"
"github.com/google/uuid"
)
type Article struct {
ID uuid.UUID `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
AuthorID uuid.UUID `json:"author_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
2. Write a goose migration
Create database/migrations/0008_articles.sql:
-- +goose Up
CREATE TABLE articles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '',
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- +goose Down
DROP TABLE IF EXISTS articles;
migrate-gen (auto-generate SQL from models) is planned — write migrations manually with goose for now.
3. Run migrations
mithril migrate-up
Generate CRUD#
mithril crud MODEL=Blog
This generates:
database/repositories/blog_repository.go(skipped if exists)internal/crud/blog/handlers.goroutes/crud_blog.go- Updates
routes/register.gowithMountCrudBlogRoutes
Dry run:
go run ./cmd/crud --dry-run Blog
API routes (JWT + ACL required):
GET /api/blogsPOST /api/blogsGET /api/blogs/:idPUT /api/blogs/:idDELETE /api/blogs/:id
Authentication Quick Test#
After mithril seed (recommended for first run):
curl -X POST http://localhost:4000/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password"}'
Or after mithril createsuperuser with your own email/password:
curl -X POST http://localhost:4000/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com","password":"your-password"}'
# Use access_token from response
curl http://localhost:4000/auth/me \
-H "Authorization: Bearer <access_token>"
Common CLI Commands#
mithril --version # alias: mithril version, mithril ping
mithril migrate-up
mithril migrate-down
mithril migrate-status
mithril seed
mithril backup
mithril swagger # requires OPENAI_API_KEY
mithril acl-role-create NAME=editor
mithril admin-enable # restart server after enabling
mithril routes # LIST_ROUTES=1 go run .
Troubleshooting#
migrate-up says "no migrations to run" on a new project
Your local Docker volume may already have Mithril migrations from a previous project. Run mithril migrate-status — if all migrations show as applied, you are ready for mithril seed. For a blank database: docker volume rm mithril_postgres_data && make dc-up-postgres.
Postgres container exits immediately
Older compose files used POSTGRES_PASSWORD="", which Postgres 16 rejects on a fresh volume. Current compose uses POSTGRES_HOST_AUTH_METHOD=trust. Reset the volume if needed:
make dc-stop-postgres
docker volume rm mithril_postgres_data
make dc-up-postgres
migrate-up fails: wrong database or auth
Ensure .env matches compose: DB_NAME=mithril_rev, DB_USER=postgres, empty DB_PASSWORD with trust auth. Or set:
DATABASE_URL=postgres://postgres@localhost:5432/mithril_rev?sslmode=disable
Server won't start (database ping)
In development the app warns and continues without DB. For a DB-less preview, comment out DB_HOST in .env. Production (APP_ENV=production) requires a working database.
Admin panel 404
Run mithril admin-enable, then restart the server.
mithril --version prints dev or scaffold output
Another mithril binary is on your PATH. Install the framework CLI and prefer $(go env GOPATH)/bin:
go install github.com/mithril-framework/mithril/cmd/mithril@v1.0.2
export PATH="$(go env GOPATH)/bin:$PATH"
mithril --version # expect: mithril 1.0.2 (github.com/mithril-framework/mithril)
Or run sudo $(go env GOPATH)/bin/mithril init to replace /usr/local/bin/mithril (removes old scaffold CLIs).
Port 4000 already in use
Another process is bound to :4000 (often a previous mithril run):
mithril kill
# requires lsof (macOS: /usr/sbin/lsof — use a full PATH if needed)
# or: /usr/sbin/lsof -ti:4000 | xargs kill
mithril run