Documentation

docs
getting started
quick start

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#

URLDescription
http://localhost:4000API root
http://localhost:4000/docsSwagger UI
http://localhost:4000/healthHealth check
http://localhost:4000/monitorSystem monitor
http://localhost:4000/adminAdmin panel (after mithril admin-enable + restart)
http://localhost:5050Embedded DBMS (after mithril dbms-enable && mithril dbms)
http://localhost:5051pgAdmin (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.go
  • routes/crud_blog.go
  • Updates routes/register.go with MountCrudBlogRoutes

Dry run:

go run ./cmd/crud --dry-run Blog

API routes (JWT + ACL required):

  • GET /api/blogs
  • POST /api/blogs
  • GET /api/blogs/:id
  • PUT /api/blogs/:id
  • DELETE /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

Next Steps#