Changelog
All notable changes to Dygo are listed here. The format follows
Keep a Changelog, and from v1.0.0 the
project follows semantic versioning. What the semver
promise covers is in the “Stability” section of the package docs
(go doc github.com/dygoframework/dygo).
Sub-modules (ws, graphql, micro/*, queue/asynq, observe,
validate/playground, sql) are versioned and tagged on their own, such as
ws/v1.0.0-beta.1. Their changes are listed here too, under the module’s name.
Unreleased
Section titled “Unreleased”dygo run <command> [args]builds the app and runs one of its console commands from the project root, so.envis read.dygo runalone lists the commands.dygo g commandand the generated files now point to it instead ofgo run ., which still works.
Removed
Section titled “Removed”- The simple
dygo newlayout. Every project now gets the modular layout (main.go,app.module.go,src/config,src/database,src/health,src/modules), anddygo gno longer writes flat files such asproducts.service.gointo packagemain. In a project made with the simple layout,dygo gnow creates a package per feature, as it does elsewhere. The-t/-templateflag is gone.
Changed
Section titled “Changed”- Getting started now runs the new project with
dygo start -watch, so it restarts on changes, and notes thatgo run .also works. - sql: a query on a table or column the database does not have now fails
with
sql.ErrSchema(“schema out of date”), and its message says to rundygo g migrationanddygo db migrate. Postgres 42P01/42703 and MySQL 1146/1054 map to it. It still answers 500. dygo g security(anddygo new -security) setsBearerAuth: truein the app’sopenapi.Options, so/docshas an Authorize button for the access token.dygo g securitywrites a randomAUTH_SECRETinto.env(not.env.example), so tokens survive restarts from the start. The “AUTH_SECRET is required in production” and “at least 32 characters” errors ofg securityandg authnow say to runopenssl rand -hex 32.
- Running
dygo db inita second time in a new project no longer adds a second driver module toapp.module.gowhensrc/databasealready opens that driver.
v1.0.0-beta.1 (2026-11-03)
Section titled “v1.0.0-beta.1 (2026-11-03)”- First public beta, v1.0.0-beta.1, published from
github.com/dygoframework/dygo. Sub-modules are tagged with their path, such
as
sql/v1.0.0-beta.1. dygotest.Integration,RequireEnvandRequireCommandmark a test as an integration test: it skips undergo test -short, and when its database, environment variable or program is missing.- Testing layout (docs/guide-testing.md):
make test-unit,make test-integrationwithcompose.test.yml, micro benchmarks inbench_test.gofiles across the modules (cache, graphql, micro, micro/grpc, micro/kafka, ws, durable providers), andmake bench,bench-save,bench-diff. CI runs unit tests, every test against Postgres, MySQL and Redis, and each benchmark once.
Changed
Section titled “Changed”-
README rewritten: security by default, a short example, and the benchmark summary; the build status and plan notes are gone.
-
Breaking: the module path is now
github.com/dygoframework/dygo, and the same for every sub-module. Update imports andgo.modfiles. -
Breaking:
WithRouteMiddlewareis nowRouteMiddleware, so every route option is a bare name and only app options start withWith. -
Breaking:
InspectReportandRouteSummaryare no longer exported. They are the file format betweendygo.Createand the CLI, which keeps its own copy.Describe,GraphInfoandErrInspectedstay public. -
Go 1.27 is now the minimum for every module, and third party dependencies are upgraded to their latest versions, which clears the govulncheck findings in
observe,micro/grpcandexamples/http-users.
-
OWASP Top 10 checks in CI: an
owaspjob runs gosec, govulncheck, the security tests and fuzzing (make owasp);docs/owasp.mdmaps each category to its checks. Actions are pinned to commits and Dependabot keeps modules and actions current.dygo g securitynow logs failed logins and addsmiddleware.SecureHeaderswhen the app has none, and its generated tests check forged own tokens, security logging and the key refetch limit. -
dygo g securityanddygo new -security: a deny-by-default security package for APIs. Every route needs a bearer token unless the ordered rules insecurity/rules.goorsecurity.Public()open it; roles with a hierarchy, authorities,security.RequireandRequireOwnerfor checks in services, register, login and me routes, JSON 401 and 403, CORS fromCORS_ALLOWED_ORIGINS, andsecuritytesthelpers that sign in as a user in tests. -
In a security project (
"security": trueindygo.json),dygo g resource,g crudandg controllerwrite protected routes (CRUD writes needadmin) and tests that check 401 and 403 and sign in withsecuritytest. New flags:-public,-public-read,-write-role. -
Security recipe (
docs/recipes/security.md), andexamples/academymoved fromdygo g authtodygo g security. -
Faster
dygo g security: checked tokens are cached until they expire (a request with an OIDC token went from 52 µs to 2 µs, with an own token from 6.2 µs to 1.7 µs); refresh tokens are spent with one conditional update, without a global lock, which also stops two app instances from accepting the same refresh token; provider keys are fetched without blocking requests. -
dygo g security -oidcanddygo new -security -oidc: the API checks tokens from an identity provider (Keycloak, Auth0, …) set byOAUTH_ISSUER_URL: OIDC discovery, JWKS with key rotation, RS256 and ES256,iss,aud,expandnbf, roles fromOAUTH_ROLES_CLAIMand scopes as authorities.securitytestruns a fake provider in tests. -
Token lifecycle in
dygo g security: login returns a refresh token;POST /auth/refreshrotates it and a reused token ends the login;POST /auth/logout; access tokens last 15 minutes (AUTH_TOKEN_TTL,AUTH_REFRESH_TTL); passwords hashed with fewer iterations are rehashed on login; register, login and refresh are rate limited per IP; users and refresh tokens followDATABASE_URL. -
dygo g migrationalso writes tables for structs given tosql.NewRepository[E]in the file that declares them. -
dygotest:Req.With(func(*http.Request))changes a request before it is sent, for helpers such assecuritytest.User. -
Services made by
dygo g crudanddygo g resourcestore their data in the database set byDATABASE_URL:memory://keeps it in memory, a Postgres or MySQL URL in that database, with no code change. New apps importsql.Module(nil), whichdygo db initturns into the driver’s module. -
sql:DATABASE_URL=memory://opens an in-memory database thatRepositoryworks on (sql.Memory,sql.MemoryModule,sql.MemoryURL,sql.ErrMemory,DB.IsMemory).Module(nil)opens it without a driver, andmigrate.Mainsays there is nothing to migrate. -
dygo g migrationcompares every entity with its table: the name is optional and only a label, and with no name and no changes it writes nothing. -
dygo newwritesDATABASE_URL=memory://to.envand.env.examplefor every template, with a comment that the data is kept in memory untildygo db initputs a Postgres or MySQL URL there. -
sql: the pool logsdatabase connectedwith the URL (password redacted) at startup, so the app shows which database it uses, and the module reads.env.localbefore.env, like the generated app’s config. -
Generated in-memory services (
dygo g crud,resource,auth) log<name> stored in memoryat startup and say in their comment that the data is lost when the app stops;dygo db initwritesDATABASE_URLwith example formats; docs/recipes/sql.md has “From memory to a database”. -
sql/migrate: numbered.up.sql/.down.sqlmigrations from anembed.FS, adygo_migrationstable, a database lock,Migrator(Up,Down,DownTo,Status,Pending),OnBoot, andMainfor the app’sdb:*commands. -
dygo db:initwritesDATABASE_URLto.envand wires the driver and migrations into the app;create,drop,migrate,rollback,status,schema createandschema droprun in the app.dygo new -db postgres|mysqlanddygo g migrationtoo. -
dygo g migrationfills the files from the entity the name is about:CREATE TABLE/DROP TABLEfor a new table,ALTER TABLE ADD/DROP COLUMNwhen the entity’s fields changed since the earlier migrations, for Postgres or MySQL. Renamed fields becomeRENAME COLUMN(asked in a terminal, or-rename old:new), and a field that changes its kind of type or nullability becomesALTER COLUMN TYPE/SET NOT NULL(Postgres) orMODIFY COLUMN(MySQL).dygo g entityprints the migration command to run next. -
dygo g migrationwarns about data loss on type changes: aDATA LOSSorMAY FAILcomment above each conversion, in the up and down files, andWARNING:lines in the output. -
dygo g migration -safewrites an expand migration and a contract migration for rolling deploys, with a trigger that keeps a renamed column and its old name in sync.sql/migrate: up files marked-- dygo:after-deploywait fordb:migrate --contract(Contract,Migrator.Held,Migration.AfterDeploy,State.AfterDeploy). -
sqlmodule:postgres.Module()andmysql.Module()readDATABASE_URLand the pool settings from the environment, ping the database at boot, close the pool after the HTTP drain and add a readiness indicator.DB.MapErrorturns driver errors intoErrNotFound(404),ErrDuplicateandErrForeignKey(409),ErrConstraint(422) andErrRetryable. Passwords never appear in errors.sql.Prefixandsql.Namedadd a second database. -
sql:DB.Get,Select,ExecandQuerywith?placeholders on both databases (rewritten to$1for Postgres, skipping strings and comments;??is a literal?),sql.InforIN (?), rows scanned into structs bydbtag or snake_case field name.DB.TxandTxWithcarry the transaction inctxwith savepoints for nested calls, retries on serialization failures and deadlocks, rollback on panic,sql.InTx,sql.DetachandErrTxDone;DB.Transactional()runs a route in one transaction. Aliases forNullString,Null[T]and the isolation levels. -
sql:sql.Repository[T]andsql.ForFeature[T](table):Find,FindBy,List,Page,Count,Exists,Create,CreateMany,Update,Patchwithsql.Set,Delete; clausesWhere,OrderBy(column names checked,ErrUnknownColumnanswers 400),LimitandOffset;db:"id,pk,auto",createdandupdatedtag options;sql.Using(name)for a named pool.DialectgainsQuoteandReturning. The MySQL dialect now addsclientFoundRows=trueto the DSN. -
docs/getting-started.mdand recipes for authentication, SQL databases and testing; an MkDocs site config (mkdocs.yml,make docs). -
benchmarks/module comparing Dygo with net/http, chi, Gin and Huma, with the method and results. -
SECURITY.md,make vulncheck(govulncheck on every module) and fuzz targets for the request binder (make fuzz). -
CI workflow (
.github/workflows/ci.yml) and the.golangci.ymlthatmake lintuses. -
Package docs: “Writing a transport” and “Stability” sections.
-
Tests for
errs,meta,validateandinterceptors. -
examples/academy, a course platform backend built with the CLI to show the framework in a real app (auth with roles, events, a background queue).
dygo g securityin a project withoutdygo/sqlnow addssql.Module(nil)and the module requirement, so the app builds.- A panic in a lifecycle hook (
OnModuleInit,OnApplicationShutdownand the others) crashed the process and skipped the remaining shutdown hooks. It is now returned as a*dygo.PanicError, and the other hooks still run. dygo g resource: the generatedDeletedoc comment read “removes a Enrollment”.
Included in the first beta
Section titled “Included in the first beta”- Core: container, modules, providers, tokens, groups,
Lazy,Optional, parameter structs, lifecycle hooks, and boot errors that list every problem. - HTTP: controllers, typed handlers, the struct tag binder, versioning, global
prefix, body limits, JSON error bodies (
errs) and request scope. - Pipeline: guards, interceptors, pipes and exception filters, typed metadata
(
meta) and validation (validate,validate/playground). - Production:
config,logger,middleware(request ID, logging, secure headers, CORS, CSRF, compression),health,openapi,ratelimitand theobservemodule for OpenTelemetry. - The
dygoCLI:new,ggenerators,db,routes,graph,check,info,start -watchandgen. - Transports and background work:
events,schedule,cqrs,cache,queue(memory andqueue/asynq),micro(NATS, gRPC, Redis, Kafka),wsandgraphql. dygotestfor unit and HTTP tests.