> **encore-go-service** — chapter 20 of 28 in [encoredev/skills](https://skillsdocs.com/encoredev/skills).
>
> Book (all chapters, one file): https://skillsdocs.com/encoredev/skills.md
> Machine manifest: https://skillsdocs.com/encoredev/skills/.well-known/agent-skills/index.json
> Install the book: `npx skills add encoredev/skills`
> Upstream: https://github.com/encoredev/skills/blob/main/encore/go-service/SKILL.md @ `main`
> Raw bytes, no header: https://raw.githubusercontent.com/encoredev/skills/main/encore/go-service/SKILL.md
> Base for relative paths: https://raw.githubusercontent.com/encoredev/skills/main/encore/go-service/
> Licence: Apache-2.0 — https://spdx.org/licenses/Apache-2.0.html
>
> Content © its authors, served unmodified. Takedown: https://github.com/DreambaseAI/skillsdocs/issues/new?labels=takedown&title=Takedown+request

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: encore-go-service
description: Plan how to split an Encore Go application into services and lay out its directory structure. Architecture and decomposition, not first-time CLI install (that's `encore-go-getting-started`).
when_to_use: >-
  User is deciding monolith vs. microservices in Go, weighing "one service or several", drawing service boundaries, planning a multi-service system (e.g. orders + payments + inventory + shipping), creating a Go package as an Encore service, naming directories/folders, designing systems-of-services hierarchies, or asking for a Go project layout recommendation. Trigger phrases: "lay out the directories", "directory structure", "service boundaries", "one service or several", "monolith vs microservices", "where to put", "systems of services", "Go package layout".
---

# Encore Go Service Structure

## Instructions

In Encore Go, **each package with an API endpoint is automatically a service**. No special configuration needed.

### Creating a Service

Simply create a package with at least one `//encore:api` endpoint:

```go
// user/user.go
package user

import "context"

type User struct {
    ID    string `json:"id"`
    Email string `json:"email"`
    Name  string `json:"name"`
}

//encore:api public method=GET path=/users/:id
func GetUser(ctx context.Context, params *GetUserParams) (*User, error) {
    // This makes "user" a service
}
```

### Minimal Service Structure

```
user/
├── user.go          # API endpoints
├── db.go            # Database (if needed)
└── migrations/      # SQL migrations
    └── 1_create_users.up.sql
```

## Application Patterns

### Single Service (Recommended Start)

Best for new projects - start simple, split later if needed:

```
my-app/
├── encore.app
├── go.mod
├── api.go           # All endpoints
├── db.go            # Database
└── migrations/
    └── 1_initial.up.sql
```

### Multi-Service

For distributed systems with clear domain boundaries:

```
my-app/
├── encore.app
├── go.mod
├── user/
│   ├── user.go
│   ├── db.go
│   └── migrations/
├── order/
│   ├── order.go
│   ├── db.go
│   └── migrations/
└── notification/
    └── notification.go
```

### Large Application (System-based)

Group related services into systems:

```
my-app/
├── encore.app
├── go.mod
├── commerce/
│   ├── order/
│   │   └── order.go
│   ├── cart/
│   │   └── cart.go
│   └── payment/
│       └── payment.go
├── identity/
│   ├── user/
│   │   └── user.go
│   └── auth/
│       └── auth.go
└── comms/
    ├── email/
    │   └── email.go
    └── push/
        └── push.go
```

## Service-to-Service Calls

Just import and call the function directly - Encore handles the RPC:

```go
package order

import (
    "context"
    "myapp/user"  // Import the user service
)

//encore:api auth method=GET path=/orders/:id
func GetOrderWithUser(ctx context.Context, params *GetOrderParams) (*OrderWithUser, error) {
    order, err := getOrder(ctx, params.ID)
    if err != nil {
        return nil, err
    }
    
    // This becomes an RPC call - Encore handles it
    orderUser, err := user.GetUser(ctx, &user.GetUserParams{ID: order.UserID})
    if err != nil {
        return nil, err
    }
    
    return &OrderWithUser{Order: order, User: orderUser}, nil
}
```

## When to Split Services

Split when you have:

| Signal | Action |
|--------|--------|
| Different scaling needs | Split (e.g., auth vs analytics) |
| Different deployment cycles | Split |
| Clear domain boundaries | Split |
| Shared database tables | Keep together |
| Tightly coupled logic | Keep together |
| Just organizing code | Use sub-packages, not services |

## Internal Helpers (Non-Service Packages)

Create packages without `//encore:api` endpoints for shared code:

```
my-app/
├── user/
│   └── user.go       # Service (has API)
├── order/
│   └── order.go      # Service (has API)
└── internal/
    ├── util/
    │   └── util.go   # Not a service (no API)
    └── validation/
        └── validate.go
```

## Guidelines

- A package becomes a service when it has `//encore:api` endpoints
- Services cannot be nested within other services
- Start with one service, split when there's a clear reason
- Cross-service calls look like regular function calls
- Each service can have its own database
- Package names should be lowercase, descriptive
- Don't create services just for code organization - use sub-packages instead
