cli

module
v3.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2026 License: MIT

README

Gothic Framework

CI

Gothic Framework — CLI (gothic)

Gothic Framework is a developer-first toolset for building fast, scalable, modern web apps in Go with the GOTTH stack: Go, TailwindCSS, Templ, and HTMX. Inspired by Next.js, it brings full-stack ergonomics — file-based routing, edge-ready static caching, ISR, image optimization, link prefetching, hot reloading, and one-command cloud deploys — to Go developers.

This module (github.com/gothicframework/cli/v3) is the gothic command-line tool: scaffolding, dev server, build pipeline, WASM/CSS/image tooling, and deploy. It is the only piece you install; the code your app imports lives in the companion modules:

gothic init wires all of these into a new project for you.


Installation

Install the gothic binary with the Go toolchain:

go install github.com/gothicframework/cli/v3/cmd/gothic@latest

This puts a gothic executable on your PATH (in $(go env GOPATH)/bin). Verify it:

gothic version

The binary is named gothic (not cli) because the entrypoint lives in cmd/gothic/go install names the binary after that leaf directory. The /v3 in the module path is Go's major-version suffix and is independent of the binary name.

Scaffold a new project
gothic init github.com/you/my-app

Pass your Go module path and init runs fully non-interactively: the module is used as-is and the project name is derived from it — the last path segment, minus any /vN major-version suffix (so github.com/you/my-app/v3my-app). Omit the argument to be prompted for the module. init scaffolds the project, pins the framework libraries in go.mod, and runs go mod tidy so the project is ready to build. The derived ProjectName is written into gothic.config.go and can be edited afterward.


Prerequisites

  • Go 1.25+ — used to build your app and run deploy lifecycle hooks.
  • Docker daemon running (deploy-time only) — Gothic builds your Lambda container image via the Docker SDK and pushes it to ECR. The daemon must be reachable at deploy time.
  • AWS credentials configured (deploy-time only) — via the shared config file (~/.aws/config / ~/.aws/credentials) or environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION). The Profile field in gothic.config.go selects the shared profile.
  • OpenTofuno manual install required. The CLI downloads a pinned OpenTofu release to .gothicCli/bin/tofu on the first deploy and reuses it afterward. Point TofuBinaryPath at a pre-installed binary to skip the download.

Local development (gothic build, gothic hot-reload, gothic wasm, gothic css) needs only Go — Docker and AWS credentials are deploy-time concerns.


The gothic command

Command What it does
gothic init [module-path] Scaffold a new project. Module path optional (prompted if omitted); project name derived from it.
gothic hot-reload Dev server. Watches .templ, .go, and CSS; rebuilds templ, emits runtime assets, recompiles WASM, and live-reloads.
gothic build Compile .templ files to their _templ.go equivalents. Does not emit runtime WASM assets or CSS.
gothic wasm Compile per-component ClientSideState to TinyGo WASM and emit the shared runtime/core assets.
gothic css Generate the Tailwind stylesheet from classes found in .templ files.
gothic optimize-images Produce low-res blurred placeholders for lazy-loaded images referenced in templates.
gothic deploy Build + push the container image and apply infrastructure with OpenTofu (see below).
gothic migrate-v2 Migrate a v1 project to v2 conventions.
gothic migrate-v3 Migrate a v2 project to v3 (config → Go, imports, SAM cleanup, topic mounts).
gothic version Print the installed CLI version.

Typical loop: gothic init …gothic hot-reload (develop) → gothic deploy --stage dev.


Configuration (gothic.config.go)

Gothic projects are configured with a type-safe Go source file, gothic.config.go, at the project root. It is parsed by the CLI via Go's AST (no type-checker, no runtime JSON), so you get IDE completion and compile-time validation. gothic init scaffolds it for you.

package main

import (
	gothic "github.com/gothicframework/core/config"
)

var Config = gothic.Config{
	ProjectName: "my-app", // used to derive deterministic cloud resource names
	// Your Go module name is read automatically from go.mod — it is NOT a field here.

	// Optional binary overrides — leave empty to use the CLI-managed defaults:
	TofuBinaryPath: "", // absolute path to a pre-installed OpenTofu binary (skips auto-download)
	DockerfilePath: "", // absolute path to a custom deploy Dockerfile (overrides the embedded one)
	WasmBinary:     "", // absolute path to a tinygo binary override
	TailwindBinary: "", // absolute path to a tailwind binary override

	OptimizeImages: gothic.OptimizeImagesConfig{
		LowResolutionRate: 20, // low-res placeholder quality for lazy-loaded images
	},

	// Runtime router config: cache backend + static-file serving. The zero value
	// equals the defaults below, so this block can be omitted entirely.
	Runtime: gothic.RuntimeConfig{
		CacheStrategy:         gothic.CACHE_CONTROL_HEADERS,
		LocalDevelopmentCache: gothic.IN_MEMORY,
		ServeStaticFiles:      gothic.CDN,
	},

	Deploy: &gothic.DeployConfig{
		Provider: gothic.AWS, // which cloud to deploy to — v3 ships AWS only
		Providers: gothic.Providers{
			AWS: gothic.AWSProvider{
				ServerMemory:  512,         // Lambda memory (MB)
				ServerTimeout: 30,          // Lambda timeout (seconds)
				Region:        "us-east-1", // AWS region to deploy into
				Profile:       "default",   // shared-config profile for credentials

				Stages: map[string]gothic.Stage{
					"dev": {
						ENV: map[string]gothic.EnvValue{
							"PORT":    gothic.Env("8080"),                          // plain string value
							"DB_URL":  gothic.SSMParam("/my-app/dev/db-url"),       // resolved from SSM Parameter Store
							"API_KEY": gothic.SecretsManager("/my-app/dev/api-key"), // resolved from Secrets Manager
						},
					},
				},
			},
		},
	},
}
Deploy providers

Deploy is provider-based. Deploy.Provider (an enum) selects the target cloud, and Deploy.Providers.<name> holds that provider's settings.

  • gothic.AWS is the only provider available in v3. Its settings live under Providers.AWS (region, profile, Lambda memory/timeout, and the per-stage config).
  • The Provider enum + Providers struct are the extension point for future clouds (GCP, Azure). Selecting an unimplemented provider fails fast with a clear error rather than silently deploying to AWS.
ENV value builders

Each entry in a stage's ENV map is produced by one of three builders. Secrets resolved from SSM or Secrets Manager are pulled by OpenTofu data sources at apply time and never land in plain text in your config:

Builder Source Use for
gothic.Env("8080") Plain string Non-sensitive config values
gothic.SSMParam("/path") AWS SSM Parameter Store Config / secrets stored in SSM
gothic.SecretsManager("/path") AWS Secrets Manager Secrets stored in Secrets Manager

For a JSON secret, chain .Get("field") to pull a single key: gothic.SecretsManager("/my-app/dev/creds").Get("api-key"). Any other function in an ENV value is rejected by the parser with an actionable error.

Lifecycle hooks

Declare top-level BeforeDeploy and/or AfterDeploy functions in gothic.config.go to run custom Go code around a deploy. Both are optional.

func BeforeDeploy(ctx context.Context, gctx *gothic.GothicContext) error
func AfterDeploy(ctx context.Context, gctx *gothic.GothicContext) error
  • BeforeDeploy runs synchronously before the image build and tofu apply. A non-nil error aborts the deploy.
  • AfterDeploy runs after tofu apply and the S3 asset sync, with gctx.Outputs carrying stack outputs (cloudfront_distribution_id, cloudfront_domain_name, s3_bucket_arn, lambda_function_arn). The GothicContext also carries Stage, ProjectName, Suffix, Region, and Env.

Deploying

gothic deploy --stage dev                 # build, push, apply, sync assets, invalidate CDN
gothic deploy --stage dev --action delete # tear the stack down

Infrastructure is managed as code from embedded OpenTofu .tf.json stack files — no template.yaml, no SAM CLI. On the first deploy the CLI:

  1. Runs BeforeDeploy (if declared).
  2. Downloads and caches the OpenTofu binary to .gothicCli/bin/tofu (reused afterward).
  3. Builds your Lambda container image via the Docker SDK and pushes it to ECR.
  4. Bootstraps the OpenTofu S3 state backend + DynamoDB lock table (skipped if they exist).
  5. Generates the .tf.json stack into .gothicCli/tofu/<stage>/ and runs tofu init + tofu apply (Lambda + Function URL + CloudFront + S3).
  6. Syncs the public/ folder to S3 and invalidates the CloudFront distribution.
  7. Runs AfterDeploy (if declared) with stack outputs populated.

--action delete removes the stack, then prompts before deleting the remote state bucket and lock table (answer N to preserve them).


Custom infrastructure (infra/)

Need a DynamoDB table, an SQS queue, an extra IAM policy, or any other AWS resource alongside your app? Drop .tf or .tf.json files into an infra/ folder at your project root. On every deploy the CLI merges them flat into the same OpenTofu working directory — so your resources live in the same module and state as the Gothic stack (gothic deploy provisions them, --action delete tears them down, all in one plan/apply).

Rules:

  • Only *.tf and *.tf.json files directly inside infra/ are merged; anything else (READMEs, .gitkeep, subfolders) is ignored.

  • A file whose name collides with a Gothic-generated file (main.tf.json, variables.tf.json, resources.tf.json, outputs.tf.json, gothic_outputs.tf.json, gothic_vars.auto.tfvars.json, env_resolved.tf.json, gothic_image.auto.tfvars.json) is rejected — rename it.

  • Reference the Gothic stack through the stable local.gothic_* contract instead of Gothic's internal resource addresses (which may change between versions):

    Local Value
    local.gothic_lambda_role_name the app Lambda's IAM role name
    local.gothic_lambda_role_arn the app Lambda's IAM role ARN
    local.gothic_lambda_function_name the app Lambda's function name
    local.gothic_lambda_function_arn the app Lambda's function ARN
    local.gothic_s3_bucket_name the assets S3 bucket name
    local.gothic_s3_bucket_arn the assets S3 bucket ARN
    local.gothic_cloudfront_distribution_id the CloudFront distribution ID
    local.gothic_cloudfront_domain_name the CloudFront domain name
Example: a DynamoDB table your app can read/write

infra/dynamodb.tf.json — declare the table and grant the Gothic Lambda role read/write on it via an inline role policy:

{
  "resource": {
    "aws_dynamodb_table": {
      "my_table": {
        "name": "my-table",
        "billing_mode": "PAY_PER_REQUEST",
        "hash_key": "id",
        "attribute": [
          { "name": "id", "type": "S" }
        ]
      }
    },
    "aws_iam_role_policy": {
      "lambda_my_table": {
        "name": "my-table-access",
        "role": "${local.gothic_lambda_role_name}",
        "policy": "${jsonencode({\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"dynamodb:GetItem\",\"dynamodb:PutItem\",\"dynamodb:UpdateItem\",\"dynamodb:DeleteItem\",\"dynamodb:Query\",\"dynamodb:Scan\"],\"Resource\":[\"${aws_dynamodb_table.my_table.arn}\",\"${aws_dynamodb_table.my_table.arn}/index/*\"]}]})}"
      }
    }
  }
}

Pass the table name to your app as an environment variable in gothic.config.go:

ENV: map[string]gothic.EnvValue{
    "TABLE_NAME": gothic.Env("my-table"),
}

Then read it at runtime and use the AWS SDK — the Lambda already has credentials via its execution role (the same one your infra/ policy attaches to), so no keys are needed:

tableName := os.Getenv("TABLE_NAME")
cfg, _ := awsconfig.LoadDefaultConfig(ctx) // picks up the Lambda role automatically
ddb := dynamodb.NewFromConfig(cfg)
// ddb.PutItem(ctx, &dynamodb.PutItemInput{TableName: aws.String(tableName), ...})

Migrating from v2

If you have an existing v2 project (with gothic-config.json and SAM templates), convert it to v3 with one command:

gothic migrate-v3           # migrate the current directory
gothic migrate-v3 --dry-run # preview the changes without writing

It backs up gothic-config.json, generates gothic.config.go, removes SAM artifacts, rewrites the v2 imports to the new org module paths, cleans up the removed topic-mount API, updates go.mod, and runs go mod tidy. It is idempotent.

The v3 CLI has no runtime JSON fallback. If GetConfig() finds a gothic-config.json, it directs you to run gothic migrate-v3.


Design docs

The framework's design records ship with the core module: docs/DESIGN-INSPIRATIONS.md, docs/adr/ (custom codec, schema seam, two-tier protocol, static full-Go core), and RELEASE_NOTES_v3.md.

Directories

Path Synopsis
cmd
gothic command
Command gothic is the Gothic Framework CLI entrypoint.
Command gothic is the Gothic Framework CLI entrypoint.
internal
astconfig
Package astconfig reads gothic.config.go via go/parser (no type checker) and produces the same cli.Config struct that v2 loaded from gothic-config.json.
Package astconfig reads gothic.config.go via go/parser (no type checker) and produces the same cli.Config struct that v2 loaded from gothic-config.json.
cli
cmd
deploy
Package tofu — binary.go implements the OpenTofu binary manager.
Package tofu — binary.go implements the OpenTofu binary manager.
deploy/docker
Package docker wraps the Docker engine SDK and the AWS ECR SDK to build the Gothic Lambda image and push it to Elastic Container Registry.
Package docker wraps the Docker engine SDK and the AWS ECR SDK to build the Gothic Lambda image and push it to Elastic Container Registry.
deploy/tfgen
Package tfgen generates a fully-formed OpenTofu working directory for the Gothic AWS stack.
Package tfgen generates a fully-formed OpenTofu working directory for the Gothic AWS stack.
scaffold/src/components
templ: version: v0.3.1020
templ: version: v0.3.1020
scaffold/src/layouts
templ: version: v0.3.1020
templ: version: v0.3.1020
scaffold/src/pages
templ: version: v0.3.1020
templ: version: v0.3.1020
termcolor
Package termcolor is the single source of truth for the Gothic CLI's terminal colors.
Package termcolor is the single source of truth for the Gothic CLI's terminal colors.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL