TAGS
Also known as
for, tag (no @ prefix for this annotation)
Apply subsequent annotations only when the endpoint has specific tags.
Overview
Tags are automatically assigned to endpoints by different routine sources (functions, procedures, tables, views). The for/tags annotation allows you to conditionally apply annotations based on these tags.
This is useful for:
- Applying different configurations based on routine volatility (
volatile,stable,immutable) - Customizing behavior for CRUD operations (
select,insert,update,delete) - Environment-specific settings when combined with custom tags
This annotation is essential when using automatic CRUD endpoint generation to apply different configurations to different CRUD operations on the same table.
Syntax
for <tag1>, <tag2>, <tag3>, ...
tags <tag1>, <tag2>, <tag3>, ...2
Space-separated lists are also valid: for select update delete
Annotations following the for/tags line apply only when the endpoint has at least one of the specified tags.
How for Creates Annotation Scopes
The for keyword creates a scope - all annotations that follow apply only to endpoints matching those tags, until the next for line or the end of the comment.
comment on table orders is '
HTTP
for select -- Start scope for SELECT endpoints
@allow_anonymous -- Applied only to SELECT
@cached -- Applied only to SELECT
for insert, update -- Start new scope for INSERT and UPDATE
@authorize -- Applied only to INSERT and UPDATE
for delete -- Start new scope for DELETE
@authorize admin -- Applied only to DELETE
';2
3
4
5
6
7
8
9
10
11
12
This creates different configurations for each CRUD operation from a single table comment.
Automatic Tags by Source
Function or Procedure Source
Tags are assigned based on routine volatility:
| Tag | Description |
|---|---|
volatile | Functions declared as VOLATILE |
stable | Functions declared as STABLE |
immutable | Functions declared as IMMUTABLE |
other | Procedures and other routines |
Table or View CRUD Source
Different CRUD operations receive different tags:
| Operation | Tags |
|---|---|
| Select | select, read, get |
| Insert | insert, put, create |
| Insert Returning | insert, put, create, insert_returning, returning |
| Insert On Conflict Do Nothing | insert, put, create, insert_on_conflict_do_nothing, on_conflict_do_nothing, on_conflict |
| Insert On Conflict Do Nothing Returning | insert, put, create, insert_on_conflict_do_nothing_returning, on_conflict_do_nothing, on_conflict, returning |
| Insert On Conflict Do Update | insert, put, create, insert_on_conflict_do_update, on_conflict, on_conflict_do_update |
| Insert On Conflict Do Update Returning | insert, put, create, insert_on_conflict_do_update_returning, on_conflict_do_update, on_conflict, returning |
| Update | update, post |
| Update Returning | update, post, update_returning, returning |
| Delete | delete |
| Delete Returning | delete, delete_returning, returning |
Examples
Volatility-Based Configuration
-- Apply caching only to immutable functions
comment on function calculate_hash(_data text) is
'HTTP GET
for immutable
@cached';2
3
4
5
CRUD-Specific Authorization
-- On a table, require authorization only for write operations
comment on table products is
'for select
@allow_anonymous
for insert, update, delete
@authorize admin';2
3
4
5
6
Environment-Specific Authorization
comment on function sensitive_data() is
'HTTP GET
for production
@authorize admin
for development
@allow_anonymous';2
3
4
5
6
Tag-Specific Paths
comment on function get_users() is
'HTTP GET
for v1
@path /api/v1/users
for v2
@path /api/v2/users';2
3
4
5
6
Multiple Tags
-- Apply rate limiting to all volatile operations
comment on function api_call() is
'HTTP POST
for volatile, insert, update, delete
@rate_limiter_policy strict';2
3
4
5
CRUD Endpoint Control with Tags
When using CRUD source with "CommentsMode": "ParseAll", use tags to apply different configurations to different CRUD operations on the same table.
Custom Path for SELECT, Authorization for UPDATE
create table crud_commented_table (
id int primary key,
name text
);
comment on table crud_commented_table is 'This is a commented table
for select
HTTP GET /select_commented_table
for update
@authorize
for returning
@disabled
for insert_on_conflict_do_update, insert_on_conflict_do_nothing -- CSV format
@disabled
';2
3
4
5
6
7
8
9
10
11
12
13
14
15
This configuration:
- Custom path
/select_commented_tablefor SELECT (instead of default/api/crud-commented-table/) - Requires authorization for UPDATE operations
- Disables all RETURNING variants
- Disables all ON CONFLICT operations
Results:
GET /api/crud-commented-table/→ 405 Method Not Allowed (default path disabled)GET /select_commented_table/→ 200 OK (custom path)POST /api/crud-commented-table/→ 401 Unauthorized (requires auth)DELETE /api/crud-commented-table/returning/→ 404 Not Found (returning disabled)PUT /api/crud-commented-table/on-conflict-do-update/→ 404 Not Found (on conflict disabled)
Enable Only ON CONFLICT Operations
create table crud_on_conflict_only (
id int primary key,
name text
);
comment on table crud_on_conflict_only is '
HTTP
@disabled
for on_conflict
@enabled
';2
3
4
5
6
7
8
9
10
11
The on_conflict tag matches all ON CONFLICT operations, enabling only upsert endpoints while keeping standard CRUD disabled.
Two Approaches: for Scopes vs Inline Tags
There are two ways to apply tag-based annotations:
Approach 1: Using for Scopes
Use for to create a scope where multiple annotations apply:
comment on table products is '
for select
@allow_anonymous
@cached
@timeout 5000
for insert, update, delete
@authorize
';2
3
4
5
6
7
8
9
Approach 2: Using Inline Tags with disabled/enabled
Use tags directly with disabled or enabled for simpler cases:
comment on table products is '
@disabled returning -- Disable all RETURNING endpoints
@disabled on_conflict -- Disable all ON CONFLICT endpoints
';2
3
4
Both approaches can be combined:
comment on table products is '
@disabled -- Disable everything first
@enabled select, delete -- Re-enable only SELECT and DELETE
for select -- Then customize SELECT
@cached
';2
3
4
5
6
7
Behavior
- Annotations after
for/tagsapply until the nextfor/tagsline or end of comment - If an endpoint matches any of the specified tags, the annotations are applied
- Tags are case-insensitive
- Multiple
for/tagsblocks can be used in the same comment - Custom tags can be defined in addition to automatic tags
- Comma-separated tags work the same as space-separated:
for select, updateequalsfor select update
Related
- CRUD Source configuration - Configure automatic CRUD endpoint generation
- OpenAPI configuration - Tags are used in OpenAPI grouping
- Comment Annotations Guide - How annotations work
- Configuration Guide - How configuration works