Overview
Collections are user-defined groups that help you organize prompts by project, use case, team, or any other categorization that makes sense for your workflow. A prompt can belong to multiple collections.
Creating Collections
Basic Creation
Create a collection with:
Name (required): A descriptive name (1-50 characters)
Description (optional): Additional context (max 200 characters)
import { createCollection } from '@/features/collections/actions' ;
const result = await createCollection ({
name: 'Customer Support' ,
description: 'Templates for handling customer inquiries' ,
});
Implementation from src/features/collections/actions.ts:8-39:
export async function createCollection ( input : CreateCollectionInput ) {
const result = createCollectionSchema . safeParse ( input );
if ( ! result . success ) {
return { error: "Invalid input" , details: result . error . format () };
}
const supabase = createClient ( cookieStore );
const { data : { user } } = await supabase . auth . getUser ();
if ( ! user ) {
return { error: "Unauthorized" };
}
const { data , error } = await supabase
. from ( "collections" )
. insert ({
name: input . name ,
description: input . description ,
user_id: user . id
})
. select ()
. single ();
if ( error ) {
return { error: error . message };
}
revalidatePath ( "/prompts" );
return { data };
}
Validation Schema
From src/features/collections/schemas.ts:3-6:
export const createCollectionSchema = z . object ({
name: z . string (). min ( 1 , "Name is required" ). max ( 50 , "Name is too long" ),
description: z . string (). max ( 200 , "Description is too long" ). optional (),
});
Managing Collections
List Collections
Fetch all collections for the current user:
import { getCollections } from '@/features/collections/actions' ;
const { data } = await getCollections ();
// Returns array sorted by name
Implementation from src/features/collections/actions.ts:41-56:
export async function getCollections () {
const supabase = createClient ( cookieStore );
const { data , error } = await supabase
. from ( "collections" )
. select ( "*" )
. order ( "name" );
if ( error ) {
console . error ( "Error fetching collections:" , error );
return { data: [] };
}
return { data };
}
Update Collection
Modify a collection’s name or description:
import { updateCollection } from '@/features/collections/actions' ;
const result = await updateCollection ( collectionId , {
name: 'Customer Support Templates' ,
description: 'Updated description' ,
});
Updates the updated_at timestamp automatically.
Delete Collection
Permanently delete a collection:
import { deleteCollection } from '@/features/collections/actions' ;
const result = await deleteCollection ( collectionId );
Deleting a collection removes all associations with prompts but does not delete the prompts themselves. Prompts remain accessible.
Managing Prompt Associations
Add Prompt to Collection
Associate a prompt with a collection:
import { addToCollection } from '@/features/collections/actions' ;
const result = await addToCollection ( promptId , collectionId );
Implementation from src/features/collections/actions.ts:101-118:
export async function addToCollection (
promptId : string ,
collectionId : string
) {
const supabase = createClient ( cookieStore );
const { error } = await supabase
. from ( "collection_prompts" )
. insert ({
prompt_id: promptId ,
collection_id: collectionId
});
if ( error ) {
return { error: error . message };
}
revalidatePath ( "/prompts" );
return { error: null };
}
Remove Prompt from Collection
Disassociate a prompt from a collection:
import { removeFromCollection } from '@/features/collections/actions' ;
const result = await removeFromCollection ( promptId , collectionId );
A prompt can belong to multiple collections. Removing it from one collection doesn’t affect its membership in others.
Database Schema
collections Table
From supabase/migrations/20260208000003_collections.sql:
CREATE TABLE collections (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth . users (id) ON DELETE CASCADE ,
name TEXT NOT NULL ,
description TEXT ,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now () NOT NULL ,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now () NOT NULL
);
collection_prompts Join Table
Many-to-many relationship between collections and prompts:
CREATE TABLE collection_prompts (
collection_id UUID NOT NULL REFERENCES collections(id) ON DELETE CASCADE ,
prompt_id UUID NOT NULL REFERENCES prompts(id) ON DELETE CASCADE ,
PRIMARY KEY (collection_id, prompt_id)
);
The composite primary key prevents duplicate associations.
Row Level Security
Users can only access their own collections:
CREATE POLICY "Users can view their own collections"
ON collections FOR SELECT
USING ( auth . uid () = user_id);
CREATE POLICY "Users can view their own collection prompts"
ON collection_prompts FOR SELECT
USING (
EXISTS (
SELECT 1 FROM collections
WHERE id = collection_id AND user_id = auth . uid ()
)
);
Search Integration
Filter by Collection
Search can be filtered to a specific collection:
import { searchPrompts } from '@/features/search/actions' ;
const { data } = await searchPrompts ( 'customer' , {
collectionId: 'collection-uuid' ,
});
Implementation in the PostgreSQL search function:
AND (filter_collection_id IS NULL OR EXISTS (
SELECT 1 FROM collection_prompts cp
WHERE cp . prompt_id = p . id AND cp . collection_id = filter_collection_id
))
From supabase/migrations/20260208000005_update_search_rpc.sql:56-59.
Use Cases
By Project
Collection: "Marketing Campaign Q1"
Prompts:
- Social media post generator
- Email subject lines
- Ad copy variations
By Team
Collection: "Engineering Team"
Prompts:
- Code review checklist
- Bug report template
- Technical documentation
By AI Model
Collection: "Claude-optimized"
Prompts:
- Prompts specifically tuned for Claude
- Examples with Claude's preferred style
By Stage
Collection: "Production Ready"
Prompts:
- Tested and approved prompts
- Used in live applications
Best Practices
Clear Naming Use descriptive collection names that explain the grouping criteria. Avoid generic names like “Collection 1”.
Consistent Organization Establish a consistent taxonomy. For example, always organize by project, or always by use case.
Multiple Collections Don’t hesitate to add prompts to multiple collections. A customer support prompt might belong to both “Production” and “Customer Service”.
Archive Over Delete Consider archiving prompts instead of removing them from collections. This preserves the organizational history.
Description for Context Use collection descriptions to document the purpose, ownership, or any special considerations.
Limitations
No nested collections : Collections cannot contain other collections. Keep hierarchy flat.
No sharing : Collections are private to each user. To share prompts, use public sharing instead.
No collection-level permissions : All prompts in a collection must belong to the same user. No team collections (yet).
Advanced Features
Bulk Operations
While not implemented in the current API, you could build bulk operations using the existing actions:
// Add multiple prompts to a collection
async function bulkAddToCollection (
promptIds : string [],
collectionId : string
) {
const results = await Promise . all (
promptIds . map ( id => addToCollection ( id , collectionId ))
);
return results ;
}
Collection Statistics
Query collection size using Supabase:
const { count } = await supabase
. from ( 'collection_prompts' )
. select ( '*' , { count: 'exact' , head: true })
. eq ( 'collection_id' , collectionId );
Recently Updated Collections
Find collections with recent activity:
const { data } = await supabase
. from ( 'collections' )
. select ( '*' )
. order ( 'updated_at' , { ascending: false })
. limit ( 10 );
Next Steps
Search Search within specific collections
Prompt Management Learn about organizing prompts
Public Sharing Share prompts outside of collections
MCP API Access collections via API