| name | encore-go-infrastructure |
| description | Declare infrastructure with Encore Go. |
Encore Go Infrastructure Declaration
Instructions
Encore Go uses declarative infrastructure - you define resources as package-level variables and Encore handles provisioning:
- Locally (
encore run) - Encore runs infrastructure in Docker (Postgres, Redis, etc.)
- Production - Deploy via Encore Cloud to your AWS/GCP, or self-host using generated infrastructure config
Critical Rule
All infrastructure must be declared at package level, not inside functions.
Databases (PostgreSQL)
package user
import "encore.dev/storage/sqldb"
var db = sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
func setup() {
db := sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{...})
}
Migrations
Create migrations in the migrations/ directory:
user/
├── user.go
├── db.go
└── migrations/
├── 1_create_users.up.sql
└── 2_add_email_index.up.sql
Migration naming: {number}_{description}.up.sql
Pub/Sub
Topics
package events
import "encore.dev/pubsub"
type OrderCreatedEvent struct {
OrderID string `json:"order_id"`
UserID string `json:"user_id"`
Total int `json:"total"`
}
var OrderCreated = pubsub.NewTopic[*OrderCreatedEvent]("order-created", pubsub.TopicConfig{
DeliveryGuarantee: pubsub.AtLeastOnce,
})
Publishing
msgID, err := events.OrderCreated.Publish(ctx, &events.OrderCreatedEvent{
OrderID: "123",
UserID: "user-456",
Total: 9999,
})
Subscriptions
package notifications
import (
"context"
"myapp/events"
"encore.dev/pubsub"
)
var _ = pubsub.NewSubscription(events.OrderCreated, "send-confirmation-email",
pubsub.SubscriptionConfig[*events.OrderCreatedEvent]{
Handler: sendConfirmationEmail,
},
)
func sendConfirmationEmail(ctx context.Context, event *events.OrderCreatedEvent) error {
return nil
}
Topic References
Pass topic access to library code while maintaining static analysis:
ref := pubsub.TopicRef[pubsub.Publisher[*OrderCreatedEvent]](OrderCreated)
func publishEvent(ref pubsub.Publisher[*OrderCreatedEvent], event *OrderCreatedEvent) error {
_, err := ref.Publish(ctx, event)
return err
}
Cron Jobs
package cleanup
import (
"context"
"encore.dev/cron"
)
var _ = cron.NewJob("cleanup-sessions", cron.JobConfig{
Title: "Clean up expired sessions",
Schedule: "0 * * * *",
Endpoint: CleanupExpiredSessions,
})
func CleanupExpiredSessions(ctx context.Context) error {
return nil
}
Schedule Formats
| Format | Example | Description |
|---|
| Cron expression | "0 9 * * 1" | 9am every Monday |
| Every interval | "every 1h" | Every hour |
| Every interval | "every 30m" | Every 30 minutes |
Object Storage
package uploads
import "encore.dev/storage/objects"
var Uploads = objects.NewBucket("user-uploads", objects.BucketConfig{})
var PublicAssets = objects.NewBucket("public-assets", objects.BucketConfig{
Public: true,
})
Operations
writer := Uploads.Upload(ctx, "path/to/file.jpg")
_, err := io.Copy(writer, dataReader)
if err != nil {
writer.Abort()
return err
}
err = writer.Close()
reader := Uploads.Download(ctx, "path/to/file.jpg")
if err := reader.Err(); err != nil {
return err
}
defer reader.Close()
data, _ := io.ReadAll(reader)
exists, err := Uploads.Exists(ctx, "path/to/file.jpg")
attrs, err := Uploads.Attrs(ctx, "path/to/file.jpg")
for err, entry := range Uploads.List(ctx, &objects.Query{}) {
if err != nil {
return err
}
fmt.Println(entry.Key, entry.Size)
}
err := Uploads.Remove(ctx, "path/to/file.jpg")
url := PublicAssets.PublicURL("image.jpg")
Signed URLs
Generate temporary URLs for upload/download without exposing your bucket:
import "time"
url, err := Uploads.SignedUploadURL(ctx, "user-uploads/avatar.jpg",
objects.WithTTL(time.Duration(7200)*time.Second))
url, err := Uploads.SignedDownloadURL(ctx, "documents/report.pdf",
objects.WithTTL(time.Duration(7200)*time.Second))
Bucket References
Pass bucket access with specific permissions to library code:
ref := objects.BucketRef[objects.Downloader](Uploads)
type myPerms interface {
objects.Downloader
objects.Uploader
}
ref := objects.BucketRef[myPerms](Uploads)
Secrets
package email
var secrets struct {
SendGridAPIKey string
SMTPPassword string
}
func sendEmail() error {
apiKey := secrets.SendGridAPIKey
}
Set secrets via CLI:
encore secret set --type prod SendGridAPIKey
Config Values
package myservice
import "encore.dev/config"
var cfg struct {
MaxRetries config.Int
BaseURL config.String
Debug config.Bool
}
func doSomething() {
if cfg.Debug() {
log.Println("Debug mode enabled")
}
}
Guidelines
- Infrastructure declarations MUST be at package level
- Use descriptive names for resources
- Keep migrations sequential and numbered
- Subscription handlers must be idempotent (at-least-once delivery)
- Secrets are accessed by calling them as functions
- Cron endpoints should be
private (internal only)
- Each service typically has its own database