This workflow follows the GitHub → HTTP Request recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "GitHub SQL Docs \u2192 Telegram (PostgreSQL)",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 5
}
]
}
},
"id": "schedule",
"name": "Every 5 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
250,
300
]
},
{
"parameters": {
"owner": "={{ $vars.GITHUB_OWNER }}",
"repository": "={{ $vars.GITHUB_REPO }}",
"options": {}
},
"id": "github-commits",
"name": "Get Recent Commits",
"type": "n8n-nodes-base.github",
"typeVersion": 1,
"position": [
500,
300
],
"credentials": {
"githubApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Filter commits dalam 5 menit terakhir yang punya file .sql\nconst commits = $input.all();\nconst fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);\n\nconst recentCommits = [];\n\nfor (const item of commits) {\n const commit = item.json;\n const commitDate = new Date(commit.commit?.author?.date || commit.created_at);\n \n if (commitDate > fiveMinutesAgo) {\n recentCommits.push({\n sha: commit.sha,\n message: commit.commit?.message || '',\n author: commit.commit?.author?.name || 'Unknown',\n date: commitDate.toISOString(),\n url: commit.html_url\n });\n }\n}\n\nif (recentCommits.length === 0) {\n return []; // Stop workflow jika tidak ada commit baru\n}\n\nreturn recentCommits.map(c => ({ json: c }));"
},
"id": "filter-recent",
"name": "Filter Recent Commits",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
750,
300
]
},
{
"parameters": {
"url": "=https://api.github.com/repos/{{ $vars.GITHUB_OWNER }}/{{ $vars.GITHUB_REPO }}/commits/{{ $json.sha }}",
"options": {},
"headerParameters": {
"parameters": [
{
"name": "Accept",
"value": "application/vnd.github.v3+json"
}
]
}
},
"id": "get-commit-files",
"name": "Get Commit Files",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1000,
300
]
},
{
"parameters": {
"jsCode": "// Extract .sql files dari commit\nconst commit = $input.first().json;\nconst files = commit.files || [];\n\nconst sqlFiles = files.filter(f => \n f.filename.endsWith('.sql') && \n (f.status === 'added' || f.status === 'modified')\n);\n\nif (sqlFiles.length === 0) {\n return []; // Tidak ada file SQL\n}\n\nreturn [{\n json: {\n sha: commit.sha,\n message: commit.commit?.message || '',\n author: commit.commit?.author?.name || 'Unknown',\n url: commit.html_url,\n sqlFiles: sqlFiles.map(f => ({\n filename: f.filename,\n raw_url: f.raw_url,\n status: f.status\n }))\n }\n}];"
},
"id": "extract-sql-files",
"name": "Extract SQL Files",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1250,
300
]
},
{
"parameters": {
"url": "={{ $json.sqlFiles[0].raw_url }}",
"options": {}
},
"id": "download-sql",
"name": "Download SQL Content",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1500,
300
]
},
{
"parameters": {
"jsCode": "// Parse CREATE TABLE statements dari SQL\nconst sqlContent = $input.first().json.data || $input.first().json.body || '';\nconst prevData = $('Extract SQL Files').first().json;\n\nconst tablePattern = /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:public\\.)?[\"']?(\\w+)[\"']?\\s*\\(([\\s\\S]*?)\\)(?:\\s*;)?/gi;\n\nconst tables = [];\nlet match;\n\nwhile ((match = tablePattern.exec(sqlContent)) !== null) {\n const tableName = match[1];\n const tableBody = match[2];\n \n const columns = [];\n const lines = tableBody.split(',');\n \n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (/^(CONSTRAINT|PRIMARY\\s+KEY\\(|FOREIGN\\s+KEY|UNIQUE\\(|CHECK\\(|INDEX)/i.test(trimmed)) continue;\n \n const colMatch = trimmed.match(/^[\"']?(\\w+)[\"']?\\s+(\\w+(?:\\([^)]+\\))?)/i);\n if (colMatch) {\n columns.push({\n name: colMatch[1],\n type: colMatch[2]\n });\n }\n }\n \n if (columns.length > 0) {\n tables.push({\n name: tableName,\n columns: columns,\n definition: match[0]\n });\n }\n}\n\nreturn [{\n json: {\n ...prevData,\n tables,\n tableCount: tables.length,\n sqlContent\n }\n}];"
},
"id": "parse-sql",
"name": "Parse PostgreSQL Tables",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1750,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "has-tables",
"leftValue": "={{ $json.tableCount }}",
"rightValue": 0,
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "has-tables",
"name": "Has Tables?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
2000,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://host.docker.internal:11434/api/chat",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"llama3:latest\",\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": \"Database documentation expert untuk PostgreSQL. Dokumentasi Bahasa Indonesia.\\n\\nTABLES:\\n{{ $json.tables.map(t => 'TABLE: ' + t.name + '\\\\nCOLUMNS: ' + t.columns.map(c => c.name + ' (' + c.type + ')').join(', ')).join('\\\\n\\\\n') }}\\n\\nResponse JSON only:\\n{\\\"tables\\\": [{\\\"name\\\": \\\"table_name\\\", \\\"description\\\": \\\"1 kalimat\\\", \\\"columns\\\": {\\\"col\\\": \\\"max 5 kata\\\"}}]}\"\n }\n ],\n \"stream\": false,\n \"options\": { \"temperature\": 0.3 }\n}",
"options": {
"timeout": 180000
}
},
"id": "ollama-ai",
"name": "Ollama AI (PostgreSQL Docs)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2250,
200
]
},
{
"parameters": {
"jsCode": "// Format hasil untuk Telegram\nconst prevData = $('Parse PostgreSQL Tables').first().json;\nconst aiResponse = $input.first().json.message?.content || '{}';\n\n// Parse AI response\nlet aiDoc = { tables: [] };\ntry {\n const jsonMatch = aiResponse.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n aiDoc = JSON.parse(jsonMatch[0]);\n }\n} catch (e) {}\n\n// Build Telegram message\nlet msg = `\ud83d\udd14 *GITHUB SQL UPDATE*\\n`;\nmsg += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n`;\nmsg += `\ud83d\udcc1 *File:* \\`${prevData.sqlFiles[0].filename}\\`\\n`;\nmsg += `\ud83d\udc64 *Author:* ${prevData.author}\\n`;\nmsg += `\ud83d\udcac *Commit:* ${prevData.message.substring(0, 50)}\\n`;\nmsg += `\ud83d\udd17 [View on GitHub](${prevData.url})\\n\\n`;\nmsg += `\ud83d\udcda *DOKUMENTASI PostgreSQL*\\n`;\nmsg += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n`;\n\nfor (let i = 0; i < prevData.tables.length; i++) {\n const t = prevData.tables[i];\n const aiTable = aiDoc.tables?.find(at => at.name === t.name) || {};\n const desc = aiTable.description || `Tabel ${t.name}`;\n \n msg += `*${i + 1}. ${t.name}*\\n`;\n msg += `\ud83d\udcdd ${desc}\\n\\n\\`\\`\\`\\n`;\n \n for (let j = 0; j < t.columns.length; j++) {\n const c = t.columns[j];\n const colDesc = (aiTable.columns?.[c.name] || c.name).substring(0, 25);\n msg += `${j + 1}. ${c.name} (${c.type})\\n \u2192 ${colDesc}\\n`;\n }\n \n msg += `\\`\\`\\`\\n\\n`;\n}\n\nmsg += `\u2705 *Total:* ${prevData.tableCount} table(s)`;\n\nreturn [{ json: { message: msg, chatId: $vars.TELEGRAM_CHAT_ID } }];"
},
"id": "format-telegram",
"name": "Format Telegram Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2500,
200
]
},
{
"parameters": {
"chatId": "={{ $json.chatId }}",
"text": "={{ $json.message }}",
"additionalFields": {
"parse_mode": "Markdown",
"disable_web_page_preview": true
}
},
"id": "send-telegram",
"name": "Send to Telegram",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
2750,
200
]
},
{
"parameters": {},
"id": "no-op",
"name": "No Tables Found",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
2250,
400
]
}
],
"connections": {
"Every 5 Minutes": {
"main": [
[
{
"node": "Get Recent Commits",
"type": "main",
"index": 0
}
]
]
},
"Get Recent Commits": {
"main": [
[
{
"node": "Filter Recent Commits",
"type": "main",
"index": 0
}
]
]
},
"Filter Recent Commits": {
"main": [
[
{
"node": "Get Commit Files",
"type": "main",
"index": 0
}
]
]
},
"Get Commit Files": {
"main": [
[
{
"node": "Extract SQL Files",
"type": "main",
"index": 0
}
]
]
},
"Extract SQL Files": {
"main": [
[
{
"node": "Download SQL Content",
"type": "main",
"index": 0
}
]
]
},
"Download SQL Content": {
"main": [
[
{
"node": "Parse PostgreSQL Tables",
"type": "main",
"index": 0
}
]
]
},
"Parse PostgreSQL Tables": {
"main": [
[
{
"node": "Has Tables?",
"type": "main",
"index": 0
}
]
]
},
"Has Tables?": {
"main": [
[
{
"node": "Ollama AI (PostgreSQL Docs)",
"type": "main",
"index": 0
}
],
[
{
"node": "No Tables Found",
"type": "main",
"index": 0
}
]
]
},
"Ollama AI (PostgreSQL Docs)": {
"main": [
[
{
"node": "Format Telegram Message",
"type": "main",
"index": 0
}
]
]
},
"Format Telegram Message": {
"main": [
[
{
"node": "Send to Telegram",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"name": "PostgreSQL"
}
],
"triggerCount": 0,
"updatedAt": "2026-01-30T12:00:00.000Z",
"versionId": "1"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
githubApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
GitHub SQL Docs → Telegram (PostgreSQL). Uses github, httpRequest, telegram. Scheduled trigger; 12 nodes.
Source: https://github.com/04irsyaD/MSF_DB/blob/main/n8n/workflows/github_postgresql_telegram.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
IR-CLU — تولید و انتشار خودکار مقاله. Uses httpRequest, github, telegram. Scheduled trigger; 6 nodes.
IR-CLU — تولید و انتشار خودکار مقاله. Uses httpRequest, github, telegram. Scheduled trigger; 6 nodes.
Auto Hunt. Uses httpRequest, googleSheets, rssFeedRead, telegram. Scheduled trigger; 78 nodes.
Auto-Hunt. Uses httpRequest, googleSheets, rssFeedRead, telegram. Scheduled trigger; 78 nodes.
This workflow runs daily at 9 AM, uses Perplexity to compile vaping industry news, optionally captures article screenshots via Browserless, and generates a HeyGen avatar video from a template. It then