DynamoDB Scan in Go (AWS SDK v2)
Scan reads every item in a table or index, page by page, then optionally drops rows with a FilterExpression. In AWS SDK for Go v2 the built-in ScanPaginator follows LastEvaluatedKey until the whole table is read.
Code
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
func main() {
ctx := context.TODO()
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-east-1"))
if err != nil {
log.Fatalf("load config: %v", err)
}
client := dynamodb.NewFromConfig(cfg)
paginator := dynamodb.NewScanPaginator(client, &dynamodb.ScanInput{
TableName: aws.String("Music"),
FilterExpression: aws.String("#filter0 >= :filterValue0"),
ExpressionAttributeNames: map[string]string{
"#filter0": "Year",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":filterValue0": &types.AttributeValueMemberN{Value: "2010"},
},
})
var items []map[string]types.AttributeValue
for paginator.HasMorePages() {
page, err := paginator.NextPage(ctx)
if err != nil {
log.Fatalf("scan: %v", err)
}
items = append(items, page.Items...)
}
fmt.Printf("Matched %d items\n", len(items))
}Explanation
FilterExpression— applied after the read, on the server. It shrinks the response but not the cost: you pay to read every item scanned, filtered or not.ExpressionAttributeNames— the filtered attribute is aliased (#filter0→Year), which keeps reserved words likeYearsafe.- Pagination — each
Scanpage reads at most 1 MB before filtering, so a filtered page can come back empty while the table still has matches.dynamodb.NewScanPaginatorkeeps calling untilLastEvaluatedKeyis exhausted — never stop at the first page. - Set
Limitto cap items scanned per page (pre-filter) — it does not cap items returned. - For a large full-table scan, split the work across goroutines with
Segment/TotalSegments(a parallel scan). - Prefer
Query.Scanreads the whole table; on anything but a tiny table it's slow and expensive.
Do it visually
Assembling a filter by hand? The DynamoDB Expression Builder builds the FilterExpression + name/value maps and copies runnable code.
To explore tables in a GUI — with filtered, paginated result grids and copy-as-code — download DynoTable, instead of scanning blind from a script.
Related examples
- DynamoDB Scan in Java — the same scan with AWS SDK for Java 2.x.
- DynamoDB Query in Go — the cheaper read you should usually reach for.
- Query vs. Scan — when (rarely) a
Scanis justified. - Why is my DynamoDB Scan slow and expensive? — the cost model and how to avoid it.
- DynamoDB ProvisionedThroughputExceededException — what a full-table scan does to a provisioned table's capacity.
- DynamoDB ThrottlingException — the other throttle, and how exponential backoff handles it.
References
- Scan — Amazon DynamoDB API Reference
- Use Scan with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- dynamodb package — AWS SDK for Go v2 (pkg.go.dev)
- dynamodb/types package — AWS SDK for Go v2 (pkg.go.dev)
- Scanning tables — Amazon DynamoDB Developer Guide
Last verified 2026-07-13 against the official AWS documentation linked above.