Postgres to Telegram, scheduled posts without chaos
Your Telegram content process probably works… until it doesn’t. One missed caption, one image posted to the wrong channel, or one “I’ll do it later” moment, and suddenly your schedule is off for days.
This is the kind of mess marketing managers and community leads feel first, but founders running lean teams get hit too. With Postgres Telegram posting automation, you stop copy-pasting and start publishing from a single source of truth.
This workflow turns your Postgres database into a controlled publishing queue for Telegram. You’ll see how it works, what you need, and what to tweak so it matches your posting style.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Postgres to Telegram, scheduled posts without chaos
flowchart LR
subgraph sg0["Telegram Flow"]
direction LR
n0@{ icon: "mdi:swap-vertical", form: "rounded", label: "Variables TG", pos: "b", h: 48 }
n1@{ icon: "mdi:swap-vertical", form: "rounded", label: "Initialization", pos: "b", h: 48 }
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Telegram Trigger"]
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Select Channels"]
n4@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Is Admin?", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Add Channel"]
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Get Bot Status"]
n7@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Define flow", pos: "b", h: 48 }
n8@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Commands", pos: "b", h: 48 }
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Channel Exists"]
n10["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request Add Channel"]
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request Delete Channel"]
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request New Delete Channel"]
n13["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request New Add Channel"]
n14["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Channel Not Exists"]
n15["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Delete Channel"]
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Get Channels "]
n17@{ icon: "mdi:cog", form: "rounded", label: "Add Divide Channels", pos: "b", h: 48 }
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Channels"]
n19@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Define Type", pos: "b", h: 48 }
n20["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Get Channels "]
n21@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If", pos: "b", h: 48 }
n22["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Upsert bot status on START"]
n23@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Buttons", pos: "b", h: 48 }
n24["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on ADD CHA.."]
n25["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on DELETE .."]
n26["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Success Send Post"]
n27["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on START "]
n28["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Welcome Message"]
n29["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on POST TE.."]
n30["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request Post Text"]
n31["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request Post Image Text"]
n32["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on POST IM.."]
n33["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on POST IM.."]
n34["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Select Channels "]
n35["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Request Post Image Image"]
n36["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Success Send Post Image"]
n37["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update bot status on START "]
n38@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If1", pos: "b", h: 48 }
n39["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Send Posts (4922)"]
n40["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Send Posts Image (4922)"]
n41["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Send Posts Image (4922) "]
n42["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Upsert bot status on START "]
n21 --> n15
n21 --> n14
n38 --> n40
n38 --> n41
n23 --> n42
n23 --> n31
n23 --> n30
n8 --> n28
n8 --> n10
n8 --> n11
n8 --> n16
n4 --> n19
n5 --> n13
n5 --> n9
n19 --> n6
n19 --> n23
n7 --> n8
n7 --> n5
n7 --> n20
n7 --> n27
n7 --> n33
n7 --> n37
n0 --> n1
n16 --> n17
n15 --> n12
n6 --> n7
n20 --> n21
n1 --> n4
n3 --> n39
n28 --> n22
n34 --> n38
n2 --> n0
n30 --> n29
n39 --> n26
n17 --> n18
n10 --> n24
n11 --> n25
n31 --> n32
n40 --> n36
n41 --> n36
n27 --> n3
n37 --> n34
n33 --> n35
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n2 trigger
class n4,n7,n8,n19,n21,n23,n38 decision
class n3,n5,n6,n15,n16,n20,n22,n24,n25,n27,n29,n32,n33,n34,n37,n42 database
classDef customIcon fill:none,stroke:none
class n2,n3,n5,n6,n9,n10,n11,n12,n13,n14,n15,n16,n18,n20,n22,n24,n25,n26,n27,n28,n29,n30,n31,n32,n33,n34,n35,n36,n37,n39,n40,n41,n42 customIcon
The Problem: Telegram posting breaks at scale
Posting to Telegram sounds simple. Then you add a second channel, a third language, a rotating promo image, and a teammate who “helps” once a week. Now your source content lives in four places, approvals happen in DMs, and nobody can answer the basic question: “What’s scheduled for tomorrow?” You lose time, but the bigger cost is inconsistency. Captions drift, images get reused with the wrong text, and the wrong channel gets the right post (which is still wrong).
The friction compounds. Here’s where it breaks down in real life.
- Copy-pasting the same message into multiple channels turns into about 30 minutes of repetitive work every posting day.
- Once images enter the mix, someone will eventually forget the caption or upload the wrong file.
- Without a central “queue,” you end up re-checking what was already posted, which is mentally draining and easy to get wrong.
- When a bot isn’t correctly set as an admin, posts silently fail, and you only notice after engagement drops.
The Solution: Schedule and publish Telegram posts from Postgres
This workflow connects n8n to your Postgres database, pulls the next approved content, and publishes it to one or more Telegram channels using your bot. It can send text-only posts or image-plus-text posts, so you’re not stuck maintaining two different processes. Inside Telegram, you also get a simple control layer: add channels, remove channels, list what’s connected, and confirm actions so you’re not guessing what happened. Post content and channel configuration live in Postgres, which means your team can review, approve, and schedule in one place instead of hunting through chat history.
The workflow starts on a schedule and also listens for Telegram commands (so you can manage channels from the same interface you publish to). It checks the bot’s status and admin access, retrieves the right post data from Postgres, then dispatches the post as text or as an image post. Finally, it confirms posting back in Telegram and updates status in the database so you have a clean audit trail.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you publish one post per day to 3 Telegram channels, and each post usually includes an image. Manually, that’s opening assets, pasting text, double-checking captions, and posting 3 times, which is easily 10 minutes per channel (about 30 minutes a day). With this workflow, you approve the post once in Postgres, then the schedule trigger runs and the bot posts automatically. Your daily effort drops to a quick review, maybe 5 minutes, while n8n handles the rest.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Postgres to store posts, channels, and status.
- Telegram Bot to publish and manage channels.
- Telegram bot token (get it from BotFather in Telegram).
Skill level: Intermediate. You’ll connect credentials and run a provided SQL script (or adapt it to your schema).
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A schedule and a Telegram command can both trigger it. The Schedule Trigger runs regular publishing, while the Telegram Incoming Trigger lets you manage channels and start certain actions from chat.
Postgres becomes the control center. The workflow retrieves your channel list and post content, and it writes status updates back to Postgres so you can see what’s pending, posted, or failed.
Logic routes the right type of post. If nodes and switch nodes decide if the workflow is adding/removing a channel, sending a text-only post, or sending an image post with caption text.
Telegram gets the final publish and confirmations. The workflow dispatches posts to the correct channel(s), then sends a confirmation message and updates the post status so nobody has to “trust the vibes.” Honestly, that’s where most manual processes fall apart.
You can easily modify the posting schedule to match your content cadence based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Telegram Trigger
This workflow starts when a Telegram message arrives. Set up the trigger to receive bot updates and pass them into the workflow.
- Add and configure Telegram Incoming Trigger as the entry point.
- Credential Required: Connect your Telegram Bot API credentials in Telegram Incoming Trigger.
- Ensure the trigger is connected to Telegram Variables as shown in the execution flow.
Step 2: Connect Telegram and Postgres Services
This workflow uses Telegram messaging nodes and multiple Postgres database operations to store channel data and status.
- Credential Required: Connect your Telegram Bot API credentials to all Telegram nodes (16+ nodes handle prompts, confirmations, and message dispatch).
- Credential Required: Connect your Postgres credentials to all Postgres nodes (16+ nodes handle channel lists, status tracking, and CRUD operations).
- Verify database access for key nodes like Retrieve Channel List, Insert Channel Record, Fetch Bot Status, and Remove Channel Record.
Step 3: Set Up Initialization and Admin Validation
These nodes prepare incoming updates and limit access to admins before routing commands.
- Configure Telegram Variables to normalize incoming update fields as needed for downstream nodes.
- Configure Startup Setup to set any default flags or variables required by the workflow logic.
- Review Validate Admin Access to ensure only approved users proceed to Determine Update Type.
Step 4: Configure Routing and Command Handling
These switch nodes control how updates are interpreted and routed to the correct path.
- Configure Determine Update Type to distinguish between command actions and message types; it routes to Fetch Bot Status and Button Choice Router.
- Configure Route Workflow to send status-based actions into Command Router, Insert Channel Record, Fetch Channels For Check, Update Status Start Text, Update Status Image Upload, and Update Status Start Image.
- Configure Command Router to route into Send Welcome Note, Prompt Add Channel, Prompt Remove Channel, and Load Channels List based on command values.
- Configure Button Choice Router to route button responses into Upsert Status Start Cmd, Request Image Text Post, and Request Text Post.
Step 5: Configure Channel Management (Add/Remove/List)
This portion handles adding channels, removing channels, and listing current channels.
- Set Insert Channel Record to write channel data, then confirm via Confirm Add Channel or notify with Notify Channel Exists.
- Set Fetch Channels For Check and Conditional Branch to validate channel existence before removal.
- Configure Remove Channel Record to delete channels and follow up with Confirm Remove Channel or Notify Channel Missing.
- Use Load Channels List → Summarize Channels → Send Channel List to provide a readable list of channels.
Step 6: Configure Text Post Flow
This path collects text content and dispatches it to all stored channels.
- Configure Request Text Post to prompt the user for the message content.
- Set Update Status Post Text to store the text submission state.
- Use Update Status Start Text → Retrieve Channel List → Dispatch Text Posts to send messages to each channel.
- Confirm delivery using Confirm Post Sent.
Step 7: Configure Image Post Flow
This path handles image-based posts, including text captions and upload flows.
- Configure Request Image Text Post to collect a caption, then store the state in Update Status Image Text.
- Use Update Status Image Upload → Request Image Upload to collect media from the user.
- Set Update Status Start Image → Choose Channels For Image → Conditional Split Image to route to either Dispatch Image Posts or Dispatch Image Posts Alt.
- Confirm completion with Confirm Image Post.
Step 8: Test and Activate Your Workflow
Run a full manual test to confirm each branch works before enabling the workflow.
- Click Execute Workflow and send a test message to your bot to trigger Telegram Incoming Trigger.
- Verify successful paths: channel list returns from Send Channel List, add/remove confirmations appear via Confirm Add Channel and Confirm Remove Channel, and posts confirm via Confirm Post Sent or Confirm Image Post.
- Check Postgres updates for status changes from nodes like Fetch Bot Status, Update Status Start Text, and Upsert Status On Start.
- When ready, toggle the workflow Active to enable production use.
Common Gotchas
- Telegram credentials can expire or the bot can lose permissions. If things break, check that the bot is still an admin in the target channel first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 45 minutes if your Postgres and Telegram bot are ready.
No. You will connect credentials and run a provided SQL script once.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. Your main cost is whatever you already pay for Postgres hosting.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s the point of using Postgres here. You can adjust the schedule in the Schedule Trigger node, and control which channels receive a post by changing the channel records the workflow loads from Postgres (for example, the “Retrieve Channel List” and “Choose Channels For Image” queries). Common tweaks include posting to only a subset of channels, adding a simple “approved” flag in your table, and changing the caption format so every post matches your brand voice.
Usually the bot is not an admin in the channel anymore, or you’re using the wrong chat ID for the target channel. Regenerate the bot token if needed, then verify the channel permissions inside Telegram and re-save credentials in n8n. If only some channels fail, check the channel list stored in Postgres because one stale record can send posts into a void.
On n8n Cloud Starter, you can run about 2,500 executions per month, which is plenty for most small teams scheduling daily posts. If you self-host, there’s no execution cap, so capacity depends on your server and how many channels you post to at once. In practice, Telegram posting is quick, and the database queries are usually the slow part. If you plan to blast many channels, add basic batching so you don’t hit Telegram rate limits.
For this use case, n8n is often a better fit because it handles branching logic (text vs image, add/remove channels, confirmations) without turning into a spaghetti of separate zaps. Self-hosting is a big deal too, especially if you want lots of scheduled runs without paying per task. Zapier or Make can still work if you only need “new row in a sheet → send a message,” and you don’t care about channel management. This workflow goes beyond that by keeping a real status log in Postgres, which is what stops the chaos long term. If you want help choosing, Talk to an automation expert.
Once Telegram posts come from Postgres, you stop treating publishing like a daily fire drill. Set it up, confirm it works, then let the workflow handle the repeatable parts.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.