# Bob for Go: SQL Query Builder, ORM Generation, and Factories

> Bob is a Go SQL access toolkit for PostgreSQL, MySQL, MariaDB, and SQLite. It combines an explicit query builder with schema-generated models, factories, and typed query code.

**stephenafamo/bob** — SQL query builder and ORM/Factory generator for Go with support for PostgreSQL, MySQL and SQLite

- Repository: https://github.com/stephenafamo/bob
- Website: https://bob.stephenafamo.com
- Stars: 1,795 · Forks: 119
- Language: Go
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/stephenafamo-bob

## Bob's Role in Go Database Development

Bob addresses the space between handwritten SQL and a heavily abstracted ORM. It is intended for Go developers who want to retain visible control over database operations while reducing repetitive code as an application grows. The README describes progressive adoption, beginning with raw SQL query strings and extending to typed queries, generated models, and factories derived from a database schema.

The documented support matrix covers PostgreSQL, MySQL, MariaDB, and SQLite. For each database family, the project lists support for query building, models, ORM generation, factory generation, and query generation. That makes Bob relevant to services that need several supported SQL dialects or want database-facing code to remain close to SQL rather than being hidden behind runtime mapping behavior.

Bob is not a single package with one narrow responsibility. The repository includes query construction, execution, dialects, models, generation tools, and factories. This breadth provides useful integration between layers, but it also means an adopter must decide which layer fits each query. A simple report may stay at the query-builder level, while a schema-owned domain model may benefit from generated code.

## How Bob Builds Dialect-Specific SQL

The first layer is a fluent query builder. According to the README, each dialect is hand-crafted and independent. This separation prevents a builder intended for PostgreSQL from being casually reused to emit MySQL or SQLite syntax. The project states that this design can support any query supported by the relevant dialect, which is different from a builder that limits output to a smaller set of operations.

The builder does not know about a database connection or schema, so it cannot infer the type of a column or reject an incorrect comparison. Queries are assembled through Query Mods. The README gives this PostgreSQL example:

```go
psql.Select(
    sm.From("users"),
    sm.Where(psql.Quote("age").GTE(psql.Arg(21))),
)
```

`psql.Select` starts the query, `sm.From` adds the table, and `sm.Where` adds a condition. The quoted identifier and argument remain explicit SQL components. This is useful when a query cannot be represented by an existing generated model or when a team wants to keep the database expression visible.

The limitation is equally important. `psql.Quote("age")` is not proof that the column exists, and `21` is not automatically checked against the column's Go or SQL type. Bob moves type awareness into its generated layers, while leaving the lower-level builder flexible for expressions outside the generated model.

## Schema-Generated Models and Query Mods

Bob's ORM code generation adds type safety by reading a database schema. The README describes generated models and generated query mods as the second layer. The example below uses a generated model field rather than a quoted string:

```go
models.Users.Query(
    models.SelectWhere.Users.Age.GTE(21),
)
```

The generated `Age` field represents the schema knowledge that the standalone builder lacks. When the generated code is synchronized with the database, the query mod communicates the intended column and comparison through typed fields. This can catch mismatches earlier than an arbitrary string expression, although the README does not claim that every runtime database constraint can be checked by the Go compiler.

Generation introduces a workflow obligation. Database schema changes must be reflected in generated files, and developers need to know when and how to run Bob's generation tools. The README links to the code-generation documentation but does not provide a universal command for a newly created application, so an adopter should consult the dialect-specific documentation before automating regeneration.

Generated query mods are also a middle ground rather than a replacement for SQL. They express common filters in a schema-aware form, but they do not remove the need to understand relationships, indexes, or dialect behavior. Their value comes from making column access explicit and typed, not from pretending that SQL has no operational complexity.

## Factory Generation for Relational Test Data

The third layer generates factories from the database schema. Bob positions this feature for tests where a record depends on related records, such as comments that require posts and posts that require users. This is a concrete difference from a factory helper that only creates values for one struct without understanding the database relationships.

The README gives this example:

```go
comments, err := f.NewComment().CreateMany(ctx, db, 10)
```

The method name indicates that it creates ten comments. The comment explains that posts and users are created appropriately. The factory therefore appears to use the generated schema relationship information to construct a valid dependency chain rather than requiring every test to repeat setup for every table.

This is useful for integration tests and test helpers, but it should not be mistaken for a complete test-data policy. The README does not document whether records are created in one transaction, how uniqueness conflicts are handled, or whether custom field values can override generated defaults. Those details should be checked in the factory documentation before using a factory for tests that require deterministic cleanup or exact transaction behavior.

Factories can also create more data than a test needs. Generated relationships are convenient, but teams should keep the requested record count and required fields visible in their test helpers so that a factory does not obscure what the test is actually exercising.

## Generated Functions for Handwritten SQL Queries

Bob's fourth layer generates code from SQL queries, with `sqlc` named as a design reference. The README shows a query called `UserPosts`:

```sql
-- UserPosts
SELECT * FROM posts WHERE user_id = $1
```

The generated function accepts an `int32`, and the documented usage is:

```go
userPosts, err := queries.UserPosts(1).All(ctx, db)
```

This approach suits queries that are clearer as SQL than as a chain of ORM operations. It can preserve the SQL statement as the source of truth while exposing a typed parameter and a result call. The exact generated output and configuration are not included in the README, so the function name and parameter type should be confirmed against the project's query-generation documentation.

Generated query functions can be extended with more filters. The README shows a typed status filter:

```go
query := psql.Select(
    UserPosts(1),
    models.PostWhere.Status.EQ("published"),
)
```

It also shows the equivalent builder expression:

```go
query := psql.Select(
    UserPosts(1),
    sm.Where(psql.Quote("posts", "status").Eq(psql.Arg("published"))),
)
```

The first version uses a generated field, while the second uses explicit SQL components. Bob does not force one choice. Developers can keep a query generated and schema-aware where that improves clarity, then use the builder for conditions that are not represented by generated mods.

## Bob Compared with GORM, Ent, SQLBoiler, and Jet

The README lists comparisons with GORM, Ent, SQLBoiler, and Jet, which signals that Bob occupies several familiar categories rather than presenting itself as a direct replacement for one tool. The README's own comparison points are more useful than an unsupported claim that it dominates any of them.

Compared with a runtime-oriented ORM, Bob's schema-aware layer is generated from the database. That can make schema changes visible in source files, but it also means code generation is part of normal development. Compared with a raw SQL package, Bob adds a fluent builder, scanning helpers, generated models, factories, and functions generated from SQL queries. The cost is a broader API surface and more decisions about where each query belongs.

A team that wants a single ORM object and reflection-based conventions may find Bob less predictable than its documentation-first model. A team that values named query mods, explicit dialect packages, and generated test data may find that model more suitable. The right comparison depends on whether SQL itself is considered part of the application's design or merely an implementation detail.

## Maintenance, Go Version, and MIT Implications

The repository is not archived, and its last push was on 2026-10-06. Recent releases include `v0.50.0` on 2026-08-11, `v0.49.0` on 2026-07-20, and `v0.48.0` on 2026-06-26. The README does not provide a compatibility table for every package or release, so upgrade planning should include checking the changelog and generated-code changes for the specific components in use.

The root `go.mod` declares `go 1.24.0`. This is a concrete constraint for consumers with older Go toolchains and means an upgrade can involve the build environment, not only Bob's API. Bob's repository includes `dialect/`, `orm/`, `gen/`, execution code, and query code, so a project may use only a subset while still needing to understand the module's release history.

The repository identifies the project as MIT licensed. That is useful baseline licensing information for adoption review, but it is not a substitute for reading `LICENCE` and checking dependencies used by an application. Generated files should also be treated as project source code and reviewed as part of schema changes.

## Installation and First Repository Use

Bob's README does not give a single application installation command or a complete connection tutorial. It links to the project documentation and Go reference, while `go.mod` identifies the module as `github.com/stephenafamo/bob` and requires Go 1.24.0. The documented commands below are contributor commands, not a claim that Bob installs as a standalone service.

From the repository root, a contributor can run the linter:

```bash
golangci-lint run
```

The README presents a clean result as the expected state. Formatting uses `gofumpt`:

```bash
gofumpt -l -w ./some/file
```

For tests, the documented single-module command is:

```bash
go test ./dialect/psql/
```

The broader repository test command is:

```bash
go test ./...
```

A first application use should begin with the documented query-builder example, but the README does not show connection setup or execution for that query. An engineer following this article can confirm that the repository provides the query construction API and a linked reference, then use the official documentation for the missing database-specific setup.

## Conclusion

Adopt Bob when a Go service needs direct SQL control plus generated database code and test factories. Do not choose it when runtime reflection and a single conventional ORM interface matter more than explicit SQL and schema-based generation. Verify dialect behavior, regeneration requirements, and compatibility with your Go version before standardizing on it.

## FAQ

### What databases does Bob support?

Bob's support table lists PostgreSQL, MySQL, MariaDB, and SQLite for query building, models, ORM generation, factory generation, and query generation.

### Does Bob provide type safety for raw SQL queries?

The standalone query builder has no database or schema concept and therefore does not provide type safety by itself. Type safety comes from generated ORM code and generated query mods when those layers are used.

### How does Bob create related test data?

Bob generates factories from the database schema. The documented `f.NewComment().CreateMany(ctx, db, 10)` example creates comments and the related users and posts they require.

## Sources

- [License: MIT](https://github.com/stephenafamo/bob/blob/main/LICENSE)
- [Project website](https://bob.stephenafamo.com)
- [README](https://github.com/stephenafamo/bob/blob/main/README.md)
- [Releases](https://github.com/stephenafamo/bob/releases)
- [stephenafamo/bob on GitHub](https://github.com/stephenafamo/bob)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stephenafamo-bob
