Post data
You can attach small amounts of data (2KB) to a post when creating it and update this data using the postData capability. This enables dynamic, stateful experiences available on posts without a server call. Post data is scoped to the post, not users.
Post data is useful for storing game state, scores, or any other information that needs to persist with the post and be shared across all users.
Post data is set when you submitPost and apps can access from the context object or do a server side call to update the post data on a Post object. For larger data, use redis.
Post data is sent to the client. Never store secrets or sensitive information.
Creating posts with data
When creating a post, include the postData parameter with your custom data object.
- Devvit Web
- Devvit Blocks
- Hono
- Express
import { context, reddit } from '@devvit/web/server';
import type { JsonObject } from '@devvit/web/shared';
type CreatePostResponse = {
postId: string;
message: string;
};
type ErrorResponse = {
error: string;
};
app.post('/api/create-post', async (c) => {
const { subredditName } = context;
if (!subredditName) {
return c.json<ErrorResponse>({ error: 'Subreddit name is required' }, 400);
}
const postData: JsonObject = {
challengeNumber: 42,
totalGuesses: 0,
gameState: 'active',
pixels: [
[0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 2, 2, 1, 0, 0, 0, 0],
[0, 0, 0, 2, 2, 1, 1, 1, 0, 0, 0],
[0, 0, 2, 2, 1, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 2, 2, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 2, 2, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 2, 2, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0]
],
};
const post = await reddit.submitCustomPost({
subredditName,
title: 'Post with custom data',
entry: 'default',
postData,
});
return c.json<CreatePostResponse>({
postId: post.id,
message: 'Post created successfully',
});
});
import { context, reddit } from '@devvit/web/server';
import type { JsonObject } from '@devvit/web/shared';
type CreatePostResponse = {
postId: string;
message: string;
};
type ErrorResponse = {
error: string;
};
router.post<string, never, CreatePostResponse | ErrorResponse, never>(
'/api/create-post',
async (_req, res) => {
const { subredditName } = context;
if (!subredditName) {
return res.status(400).json({
error: 'Subreddit name is required'
});
}
const postData: JsonObject = {
challengeNumber: 42,
totalGuesses: 0,
gameState: 'active',
pixels: [
[0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 2, 2, 1, 0, 0, 0, 0],
[0, 0, 0, 2, 2, 1, 1, 1, 0, 0, 0],
[0, 0, 2, 2, 1, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 2, 2, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 2, 2, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 2, 2, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0]
],
};
const post = await reddit.submitCustomPost({
subredditName,
title: 'Post with custom data',
entry: 'default',
postData,
});
res.json({
postId: post.id,
message: 'Post created successfully'
});
},
);
import { Devvit } from '@devvit/public-api';
Devvit.addMenuItem({
label: 'Create custom post',
location: 'subreddit',
onPress: async (_event, context) => {
const post = await context.reddit.submitPost({
subredditName: context.subredditName!,
title: 'My custom post',
preview: (
<vstack height="100%" width="100%" alignment="middle center">
<text size="large">Loading ...</text>
</vstack>
),
postData: {
"riddle": "A very clever riddle",
"scores": {
"team1": "Team 1",
"team2": "Team 2",
},
}
});
context.ui.showToast(`Created post with ID ${post.id}`);
context.ui.navigateTo(post);
},
});
Updating post data
To update post data after creation, fetch the post and use the setPostData() method.
- Devvit Web
- Devvit Blocks
- Hono
- Express
import { context, reddit } from '@devvit/web/server';
import type { JsonObject } from '@devvit/web/shared';
type UpdatePostDataRequest = {
favoriteColor?: string;
username?: string;
};
type UpdatePostDataResponse = {
success: true;
message: string;
};
type ErrorResponse = {
error: string;
};
app.post('/api/update-post-data', async (c) => {
const { postId } = context;
const { favoriteColor, username } = await c.req.json<UpdatePostDataRequest>();
if (!postId) {
return c.json<ErrorResponse>({ error: 'Post ID is required' }, 400);
}
try {
const post = await reddit.getPostById(postId);
// Get existing post data to merge with updates
const currentData = (context.postData || {}) as JsonObject;
await post.setPostData({
...currentData,
favoriteColor: favoriteColor || 'unknown',
lastUpdatedBy: username || 'anonymous',
lastUpdatedAt: new Date().toISOString(),
});
return c.json<UpdatePostDataResponse>({
success: true,
message: 'Post data updated successfully',
});
} catch (error) {
console.error('Error updating post data:', error);
return c.json<ErrorResponse>({ error: 'Failed to update post data' }, 500);
}
});
import { context, reddit } from '@devvit/web/server';
import type { JsonObject } from '@devvit/web/shared';
type UpdatePostDataRequest = {
favoriteColor?: string;
username?: string;
};
type UpdatePostDataResponse = {
success: true;
message: string;
};
type ErrorResponse = {
error: string;
};
router.post<string, never, UpdatePostDataResponse | ErrorResponse, UpdatePostDataRequest>(
'/api/update-post-data',
async (req, res) => {
const { postId } = context;
const { favoriteColor, username } = req.body;
if (!postId) {
return res.status(400).json({
error: 'Post ID is required'
});
}
try {
const post = await reddit.getPostById(postId);
// Get existing post data to merge with updates
const currentData = (context.postData || {}) as JsonObject;
await post.setPostData({
...currentData,
favoriteColor: favoriteColor || 'unknown',
lastUpdatedBy: username || 'anonymous',
lastUpdatedAt: new Date().toISOString(),
});
res.json({
success: true,
message: 'Post data updated successfully'
});
} catch (error) {
console.error('Error updating post data:', error);
res.status(500).json({
error: 'Failed to update post data'
});
}
},
);
import { Devvit, useForm } from '@devvit/public-api';
Devvit.addCustomPostType({
name: 'InteractivePost',
render: (context) => {
const updateForm = useForm(
{
fields: [
{ type: 'string', name: 'favColor', label: 'Favorite color' },
],
},
async (values) => {
if (!context.postId) {
context.ui.showToast('Post ID not found');
return;
}
const post = await context.reddit.getPostById(context.postId);
const currentUsername = await context.reddit.getCurrentUsername();
// Get existing post data to merge with updates
const currentData = context.postData || {};
await post.setPostData({
...currentData,
favColor: values.favColor || 'unknown',
user: currentUsername || 'anonymous'
});
context.ui.showToast('Updated post data!');
}
);
return (
<button onPress={() => context.ui.showForm(updateForm)}>
Update post data
</button>
);
},
});
setPostData() replaces the entire post data object. To update specific fields while preserving others, merge the existing data with your updates.
Accessing post data
Post data is available through context.postData in both client and server contexts.
- Devvit Web
- Devvit Blocks
import { context } from '@devvit/web/client';
export const App = () => {
return (
<div>
<text className='mt-1 font-bold'>Post Data:</text>
<text>{JSON.stringify(context.postData, null, 2) ?? 'undefined'}</text>
</div>
);
}
import { Devvit } from '@devvit/public-api';
Devvit.addCustomPostType({
name: 'MyCustomPost',
render: (context) => {
return (
<vstack alignment='middle center'>
<text size='medium'>context.postData:</text>
<text size='medium'>{JSON.stringify(context.postData, null, 2)}</text>
</vstack>
);
},
});
Limitations
Post data supports:
- JSON-serializable objects only
- Maximum size of 2KB
- Data persists with the post lifecycle (deleted when post is deleted)
- Updates to post data don't trigger automatic re-renders. Implement polling or refresh mechanisms as needed