Skip to content
/ gos Public

[MOVED] Tool for mapping between Go structs and plain SQL. Not an ORM.


Notifications You must be signed in to change notification settings


Repository files navigation

Moved to This repo is usable but frozen.


Go ↔︎ SQL: tool for decoding results into Go structs. Supports streaming.

Not an ORM, and should be used instead of an ORM, in combination with a simple query builder (see below).

Key features:

  • Decodes SQL records into Go structs.
  • Supports nested records/structs.
  • Supports nilable nested records/structs in outer joins.
  • Supports streaming.

See the full documentation at

See the sibling library a simple query builder that supports scanning structs into named arguments.

Differences from jmoiron/sqlx

Gos is somewhat similar to jmoiron/sqlx. Key differences:

  • Supports null records in outer joins, as nested struct pointers.
  • Selects fields explicitly, by reflecting on the output struct. This allows you to write select *, but if the struct is lacking some of the fields, the DB will optimize them out of the query.
  • Simpler API, does not wrap database/sql.
  • Explicit field-column mapping, no hidden renaming.
  • Has only one tiny dependency (most deps in go.mod are test-only).
  • ... probably more

Features Under Consideration

  • Short column aliases.

Like many similar libraries, when selecting fields for nested records, Gos relies on column aliases like "column_name.column_name". With enough nesting, they can become too long. At the time of writing, Postgres 12 has an identifier length limit of 63 and will silently truncate the remainder, causing queries to fail, or worse. One solution is shorter aliases, such as "1.2.3" from struct field indexes. We still want to support long alises for manually-written queries, which means the library would have to support both alias types, which could potentially cause collisions. Unclear what's the best approach.



Improved how Query and Scanner handle previously-existing values in the output, especially in regards to pointers.

When a row contains null, the corresponding Go value is now zeroed rather than ignored. The old non-zeroing behavior was aligned with encoding/json. The new behavior diverges from it.

When a row contains non-null and the corresponding Go value is a non-nil pointer, the value is written to the pointer's target, without replacing the pointer.


Query allows nil output, using conn.ExecContext to discard the result.


Support streaming via QueryScanner and Scanner.


Dependency update.


Breaking: moved query generation utils into


Fixed an oversight in queryStruct and queryScalar that could lead to shadowing DB errors with ErrNoRows in some edge cases.


Added SqlQuery.QueryAppend.


Changed the license to Unlicense.


Breaking changes in named args utils for symmetry with database/sql.

  • Added Named().
  • Renamed SqlArg -> NamedArg.
  • Renamed SqlArgs -> NamedArgs.
  • Renamed StructSqlArgs -> StructNamedArgs.

Also moved some reflection-related utils to a tiny dependency.


First tagged release. Added SqlArgs and SqlQuery for query building.


Issues and pull requests are welcome! The development setup is simple:

git clone
cd gos
go test

Tests currently require a local instance of Postgres on the default port. They create a separate "database", make no persistent changes, and drop it at the end.



I'm receptive to suggestions. If this library almost satisfies you but needs changes, open an issue or chat me up. Contacts:


[MOVED] Tool for mapping between Go structs and plain SQL. Not an ORM.