Getting Started
This page walks through creating a craftgo project, defining one endpoint, and running it. About 5 minutes.
Prerequisites
- Go 1.26 or later
- A terminal
Install the CLI
go install github.com/craftgodotdev/craftgo/cmd/craftgo@latestVerify:
craftgo --helpCreate a project
mkdir hello && cd hello
go mod init example.com/hello
go get github.com/craftgodotdev/craftgoScaffold the design folder
craftgo init designThis creates design/craftgo.design.yaml with default settings. Then write a .craftgo file:
design/users/service.craftgo:
package design
type CreateUserReq {
name string @length(1, 80)
email string @format(email)
}
type User {
id string
name string
email string
}
@prefix("/v1")
service UserService {
post CreateUser /users {
request CreateUserReq
response User
}
}Folder layout so far:
hello/
├── design/
│ ├── craftgo.design.yaml
│ └── users/
│ └── service.craftgo
├── go.mod
└── go.sumGenerate
craftgo gen design
go mod tidyThe CLI walks up from the given path looking for craftgo.design.yaml, reads go.mod for the Go module path, then writes the files below; go mod tidy then adds the modules the generated code imports:
hello/
├── design/... (your DSL, unchanged)
├── internal/
│ ├── types/design/ generated structs + Validate()
│ │ ├── types.go
│ │ └── validate.go
│ ├── transport/user_service/ generated HTTP handlers
│ │ └── create_user.go
│ ├── service/user_service/ gen-once business logic stubs
│ │ └── create_user.go
│ ├── routes/ generated routing
│ │ ├── routes.go
│ │ └── user_service/routes.go
│ └── wiring/wiring.go the one call main.go makes
├── svccontext/
│ ├── svccontext.go gen-once dependency container
│ └── middlewares.go generated middleware fields
├── config/ gen-once runtime config
│ ├── config.go
│ ├── config.yaml
│ └── example.config.yaml
├── docs/openapi.yaml generated OpenAPI 3.1 spec
├── main.go gen-once entry point
└── go.modImplement business logic
Open internal/service/user_service/create_user.go:
func (l *CreateUserService) CreateUser(req *types.CreateUserReq) (*types.User, error) {
return &types.User{
ID: "u1",
Name: req.Name,
Email: req.Email,
}, nil
}This is the only file you edit. Everything else under internal/ is regenerated - see Architecture for the split.
Run
go run .{"level":"info","ts":…,"caller":"hello/main.go:49","msg":"metrics scrape listening","url":"[::]:9090/metrics"}
{"level":"info","ts":…,"caller":"hello/main.go:128","msg":"listening","addr":"[::]:8080"}In another terminal:
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{"name":"alice","email":"alice@example.com"}'{"id":"u1","name":"alice","email":"alice@example.com"}(/api comes from openapi.basePath: /api in craftgo.design.yaml; /v1 from @prefix("/v1") in the DSL.)
Try a bad payload:
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{"name":"","email":"not-an-email"}'{"message":"name: length out of range [1, 80]"}The status is 400. Validate() is fail-fast - it returns the first violation (here name), so fixing one surfaces the next. The validators run without you writing any code.
What just happened
One DSL file gives typed structs, an HTTP handler, a logic stub, route registration and an OpenAPI spec; you fill the stub, and the handler decodes, validates, dispatches and encodes around it.
No reflection-based binding or validation, no struct tags to write, no middleware boilerplate. The handler is a plain http.HandlerFunc registered on *http.ServeMux.
Designing with an LLM?
If you draft .craftgo files with Claude, ChatGPT, Cursor, or any other LLM, paste this URL into your prompt:
https://craftgodotdev.github.io/craftgo/llmsIt is a single-page consolidated reference (every keyword, decorator, CLI flag, and generated layout) designed for AI ingestion. Your assistant will know the full spec and stop inventing non-existent decorators.
Next steps
- Read Architecture for how the design, the generated code and the runtime fit together.
- Read DSL Basics to learn the syntax in depth.
- Browse Decorators to see every decorator with arguments and sites.
- Install the VS Code extension (search "craftgo" in the Extensions panel) - or set up the LSP for another editor - for completion, hover, and live diagnostics.
- See Configuration to relocate generated files or add custom config.