Turn one devlog into posts for every channel with n8n + AI
If you're a solo game developer, you know the drill: you ship an update, write a devlog⦠and then you have to rewrite it four times. A punchy tweet. A longer Reddit post that doesn't sound like an ad. A casual Discord ping. A newsletter blurb. By the third rewrite you've lost the will to post at all.
I automated the rewriting with n8n, Google Gemini, and Notion. I write the devlog once, hit run, and get channel-ready drafts waiting in Notion. It doesn't auto-post, it makes drafts I review and send myself, which keeps everything authentic and inside each platform's rules.
Here's a short demo of the finished workflow: π https://www.loom.com/share/f108f0a003b448b2bc414a8be742d772
What it does
For one devlog you paste in, it:
- Sends your update to Gemini
- Reformats it for four channels: Twitter/Bluesky, Reddit, Discord, newsletter
- Parses the result into separate fields
- Saves them as one Notion row with a draft per channel
The flow looks like this:
Manual Trigger β Devlog Input β AI Reformat (Gemini) β Parse Drafts β Save Drafts to Notion
What you need
- n8n running locally (Docker is easiest)
- A Notion account + an internal integration
- A Google Gemini API key (free tier is fine to start)
Step 1 - Run n8n
docker volume create n8n_data
docker run -d --name n8n \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
docker.n8n.io/n8nio/n8n
Open http://localhost:5678 and create your account.
Step 2 - The devlog input
Add a Code node where you write your update once. Keeping it in a Code node means you just edit two variables each time:
const devlog_title = "Update 0.3 - Online Co-op";
const devlog_body = `We just shipped online co-op for up to 4 players, fixed the save-corruption bug, and added 2 new levels. Next up: controller support and a Steam demo.`;
return [{ json: { devlog_title, devlog_body } }];
(Later you can swap this for a Form Trigger so you get a little web form, or a Notion Trigger that fires when you add a devlog page.)
Step 3 - Reformat with Gemini
Add the Google Gemini node. The trick is to make it return strict JSON so the next node can split it cleanly:
You are a social media manager for a solo indie game developer. Here is a devlog update:
Title: {{ $json.devlog_title }}
Body: {{ $json.devlog_body }}
Rewrite it for each channel. Return ONLY valid JSON (no markdown, no code fences, no text outside the JSON) with these exact keys:
{
"twitter": "280 characters max, punchy, 1-2 relevant hashtags",
"reddit": "friendly longer post for r/IndieDev, first person, no hashtags, no hard selling",
"discord": "casual short announcement for a community server, 1-2 emojis ok",
"newsletter": "2-3 sentence email blurb"
}
Step 4 - Parse the drafts
LLMs sometimes wrap JSON in code fences, so a small Code node cleans and parses it, with a fallback so you never lose output:
const raw = ($json.content?.parts?.[0]?.text) || "";
// \x60 is a backtick (char code 96). This strips a code fence
// if the model wraps its JSON output in one.
let clean = raw.trim()
.replace(/^\x60{3}json\s*/i, "")
.replace(/^\x60{3}\s*/, "")
.replace(/\x60{3}$/, "")
.trim();
let parsed;
try {
parsed = JSON.parse(clean);
} catch (e) {
parsed = { twitter: "", reddit: raw, discord: "", newsletter: "" };
}
const input = $('Devlog Input').item.json;
return [{
json: {
devlog_title: input.devlog_title,
twitter: parsed.twitter || "",
reddit: parsed.reddit || "",
discord: parsed.discord || "",
newsletter: parsed.newsletter || "",
}
}];
Step 5 - Save to Notion
Create a Notion database called Devlog Drafts with these properties:
Name(title)Twitter(text)Reddit(text)Discord(text)Newsletter(text)Status(text)Created(date)
Create an internal integration at notion.so/my-integrations, connect it to the database, then map the fields in n8n's Notion node. Set the title to {{ $json.devlog_title }} and each channel field to its matching value ({{ $json.twitter }}, etc.).
Run the workflow and you'll get a new row with four drafts - review, tweak, and post whenever you like.
Gotchas
- All text lands in the Reddit field β the model didn't return clean JSON that run. Re-run, or tighten the prompt ("Return ONLY valid JSON"). The fallback in Step 4 keeps your output safe.
- Empty Notion rows β property names must match exactly.
- Very long drafts β normal devlogs are fine; extremely long posts may get truncated in Notion text fields.
Want the done-for-you version?
I packaged this, plus a Steam competitor-tracking workflow, into an importable pack with setup guides, the AI prompts, troubleshooting, and example screenshots: π https://shrisab.gumroad.com/l/indie-launch-ops
Either way, write the devlog once, and stop dreading the four rewrites. Questions welcome in the comments.
Comments
No comments yet. Start the discussion.