--- title: Installation description: Install the Go toolchain, PostgreSQL and the summer CLI, then build, configure, migrate and serve your first SummerCMS application. section: setup order: 20 --- # Installation SummerCMS is a Go module. An application requires it, lists its plugins in a `summer.yaml` manifest and builds everything into one binary with the `summer` CLI. This page installs the tool, then builds and runs `examples/hello`, the small reference application in the framework repository. ## Requirements - Go 1.27. - PostgreSQL 16 for any application that uses the data layer. The database's default locale must be the ICU `pl-PL` locale, which lagoon checks when it connects. - Docker, only for the integration tests that start PostgreSQL or Mailpit containers. You do not need Node.js to build an application or these docs. It is needed only when you work on the admin SPA itself. ## Install the summer CLI Clone the framework repository, then install the `summer` tool from its root: ```sh go install ./cmd/summer summer --help ``` The tool builds and watches applications, scaffolds plugins, models, migrations and admin controllers, and builds this documentation. Check that the framework compiles and its unit tests pass: ```sh go vet ./... go test -short ./... ``` `go test -short` skips the tests that need Docker. Run `go test ./...` without `-short` when Docker is available. ## Check your install Console commands in SummerCMS are plain `bonfire.Command` values: a name in `namespace:verb` form, its arguments and flags, and a run function that reads input and writes output. The `summer` tool and every application binary are built from such values, and `bonfire.Call` runs one in-process, which is how tests call commands. This example comes from the framework's own tests, so it compiles and runs whenever you run `go test ./...`: ```go src=modules/bonfire/example_test.go#ExampleCall commands := []bonfire.Command{{ Name: "acme:greet", Description: "Greet someone by name", Args: []bonfire.Arg{{Name: "name", Required: true}}, Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { name, _ := in.Argument("name") out.Printf("Hello, %s\n", name) return nil }, }} if err := bonfire.Call(context.Background(), commands, "acme:greet", []string{"blog"}, os.Stdout); err != nil { fmt.Println(err) } // Output: Hello, blog ``` If the tests above pass, this example ran and printed `Hello, blog`. See the [bonfire](../../modules/bonfire/README.md) reference for flags, prompts and styled output. ## Build the example application `examples/hello` has three compiled plugins. From the framework root, build it with `summer build`, which generates `plugins.gen.go` and `main.go` from `summer.yaml` and writes the binary to `bin/hello`: ```sh cd examples/hello summer build ./bin/hello --help ./bin/hello greeter:hello ./bin/hello key:generate ``` `greeter:hello` prints the example's layered configuration and `key:generate` prints a fresh application key. Neither needs a database. ## Create the database The commands that touch data open PostgreSQL. Create a database with the locale lagoon checks for: ```sql CREATE DATABASE hello TEMPLATE template0 ENCODING 'UTF8' LOCALE_PROVIDER icu ICU_LOCALE 'pl-PL'; ``` ## Configure the application Configuration comes from YAML files in `config/`. Any key can be overridden with a `SUMMER_` environment variable, in which a double underscore separates path segments: `SUMMER_DATABASE__DSN` sets `database.dsn`. [Configuration](configuration.md) explains the layers. `serve` and `route:list` need request body limits, and surf reads them as numbers, which the string-valued environment overlay cannot supply. Create `config/http.yaml` in `examples/hello`: ```yaml body_limits: default_bytes: 1048576 upload_bytes: 10485760 ``` Then point the binary at the database, give it the application key and an uploads bucket. Replace the `` markers with your own values, and never commit them: ```sh export SUMMER_DATABASE__DSN='postgres://acme:@127.0.0.1:5432/hello?sslmode=disable' export SUMMER_APP__KEY='' export SUMMER_STORAGE__UPLOADS__BUCKET_URL='mem://' ``` ## Migrate and serve Run the migrations, list the routes and start the server on the loopback address: ```sh ./bin/hello migrate ./bin/hello route:list ./bin/hello serve --addr 127.0.0.1:8080 curl http://127.0.0.1:8080/items/1 ``` From the application directory, `summer migrate`, `summer migrate:status` and `summer serve` run the same commands through the built binary, building it first when it is missing. > [!WARNING] > Known issues in the current framework: > > - `examples/hello` ships no `http.body_limits` configuration, so `serve` and `route:list` fail with `surf: config http.body_limits.default_bytes is required` until you add `config/http.yaml` as shown above. The same gap makes the example's `TestTypedItemRoute` fail. > - lagoon refuses any database whose default locale is not ICU `pl-PL`. > - The committed `examples/hello/main.go` is older than what `summer build` generates now, so building the example leaves that file modified. Restore it with `git checkout -- examples/hello/main.go` if you do not intend to commit it. ## Next steps - Read [Coming from WinterCMS](coming-from-wintercms.md) if you are porting a WinterCMS plugin. - Read the [Architecture introduction](../architecture/introduction.md) to see how the pieces fit. - Scaffold your own plugin with `summer make:plugin` as described in [Plugin registration](../plugins/registration.md).