I build n8n workflows to do real work. This one is about wiring GitHub into n8n, keeping the flow small, and making sure it keeps running when something breaks.
Get n8n running somewhere you control. I use Docker on a small VM for testing, then move to a managed host for production. A quick local run looks like this:
docker run -it --rm -p 5678:5678 -v ~/.n8n:/home/node/.n8n n8nio/n8n
That mounts the config so workflows and credentials survive a restart. For production, wrap n8n in docker-compose or a systemd unit and set N8N_HOST, N8N_PORT and credentials through environment variables. Only install extra packages if you actually need custom nodes.
For GitHub, create a personal access token and store it as an n8n credential. If the workflow needs to read or write repo content, or trigger actions, give the token repo and workflow scopes. Add the GitHub node in the editor, pick the credential, and test it with something simple like listing repositories. If that works, move on to the trigger you want. For webhooks, use the Webhook node and point GitHub webhooks at it through an accessible URL, or a tunnelling tool while you are developing.
Keep workflows focused on one job. Monolith flows are a pain to debug. Split the work into small flows you can test on their own. Use event-driven triggers where you can, not polling. Use SplitInBatches when you are processing large lists so memory use stays predictable. Set reasonable timeouts on external calls and use the Wait node where a pause makes sense. Keep input and output shapes obvious. Add an Item Limit on nodes that might return large datasets. For branching, use IF nodes and clear checks instead of burying logic in JavaScript. I also name nodes by action and expected input so the flow is readable at a glance, for example Get PR files (repo/name) or Create release draft. Keep naming consistent across workflows.
Test every integration and break it on purpose. My routine for GitHub-connected flows is:
- Run the workflow manually in the editor with a sample payload that looks like the GitHub webhook.
- Use Test Node to run only the node I changed and check the output. Make sure the JSON keys and types match what comes next.
- Inject failures: revoke the token, force a 404, or return an empty array. See what the workflow does and fix the fallback.
- Run a small batch against real data, not the whole set.
Log node output to a simple file or a logging service. Keep example outputs with the workflow. That makes debugging easier later. If a node hits the GitHub API repeatedly, add a short backoff and a Retry node. Keep the retry count explicit and set a circuit-breaker threshold so a bad state does not loop forever.
Maintenance is mostly discipline. Keep credentials out of the editor where you can, using environment variables or a secrets manager. Export workflows as JSON and commit them to GitHub for version control. I keep one repo per project and a simple folder structure: workflows/, credentials-samples/, README.md. A short CI step can check that exported JSON parses and that required fields exist before a PR is accepted.
For deployments, script imports with the n8n CLI or API so a merge to main can trigger an import into a staging instance. Back up the n8n database, or the filesystem that holds .n8n, on a regular schedule. Rotate tokens on a cadence. Keep sample inputs and outputs with each workflow file; that is often what people want when you publish a workflow. If you share it on GitHub, add a README that explains the trigger, inputs, and expected outputs, plus a minimal test payload and the steps to run it locally.
If something breaks, narrow it down. Run individual nodes with known-good inputs. Compare the output against the saved examples. Replace messy JavaScript with smaller transforms you can validate. Keep commits small and say what changed and why. That makes rollbacks and audits less awful.



