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": "Budget Export - Main",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "55 23 28-31 * *"
}
]
}
},
"id": "schedule-trigger",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
240,
300
],
"notes": "Triggers on days 28-31 at 11:55 PM - guard node ensures only last day executes"
},
{
"parameters": {
"jsCode": "// Check if today is the last day of the month\nconst today = new Date();\nconst tomorrow = new Date(today);\ntomorrow.setDate(tomorrow.getDate() + 1);\n\n// If tomorrow is day 1, today is last day of month\nconst isLastDay = tomorrow.getDate() === 1;\n\nreturn [{ json: { isLastDay, currentDate: today.toISOString() } }];"
},
"id": "check-last-day",
"name": "Check If Last Day of Month",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
350,
300
],
"notes": "Ensures export only runs on actual last day of month (handles Feb, 30-day months correctly)"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "is-last-day",
"leftValue": "={{ $json.isLastDay }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "last-day-gate",
"name": "Last Day Gate",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
460,
300
],
"notes": "Only proceed to export if isLastDay === true"
},
{
"parameters": {
"command": "/scripts/export_monthly_snapshot.sh"
},
"id": "execute-export",
"name": "Execute Export Script",
"type": "n8n-nodes-base.ssh",
"typeVersion": 1,
"position": [
680,
200
],
"credentials": {
"sshPassword": {
"name": "<your credential>"
}
},
"notes": "Runs export script in alpine-utility container via SSH"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "check-exit-code",
"leftValue": "={{ $json.code }}",
"rightValue": 0,
"operator": {
"type": "number",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "check-success",
"name": "Check Success",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
680,
300
],
"notes": "Verify export completed successfully"
},
{
"parameters": {},
"id": "success-notification",
"name": "Success Notification",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
900,
200
],
"notes": "Silent success \u2014 no email needed"
},
{
"parameters": {
"fromEmail": "golickmybutt@gmail.com",
"toEmail": "golickmybutt@gmail.com",
"subject": "\u274c Budget Export Failed",
"emailFormat": "html",
"html": "=<h2>\u274c Budget Export Failed</h2>\n<p><strong>Time:</strong> {{ $now.format('YYYY-MM-DD HH:mm:ss') }}</p>\n<p><strong>Exit Code:</strong> {{ $('Execute Export Script').first().json.code }}</p>\n<p><strong>Error Output:</strong></p>\n<pre style=\"background: #f5f5f5; padding: 10px; border: 1px solid #ddd;\">{{ $('Execute Export Script').first().json.stderr || 'No error output' }}</pre>\n<p><strong>Standard Output:</strong></p>\n<pre style=\"background: #f5f5f5; padding: 10px; border: 1px solid #ddd;\">{{ $('Execute Export Script').first().json.stdout || 'No output' }}</pre>",
"options": {}
},
"id": "failure-notification",
"name": "Failure Notification",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
900,
400
],
"credentials": {
"smtp": {
"name": "<your credential>"
}
},
"notes": "Send email alert if budget export fails"
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Check If Last Day of Month",
"type": "main",
"index": 0
}
]
]
},
"Check If Last Day of Month": {
"main": [
[
{
"node": "Last Day Gate",
"type": "main",
"index": 0
}
]
]
},
"Last Day Gate": {
"main": [
[
{
"node": "Execute Export Script",
"type": "main",
"index": 0
}
],
[]
]
},
"Execute Export Script": {
"main": [
[
{
"node": "Check Success",
"type": "main",
"index": 0
}
]
]
},
"Check Success": {
"main": [
[
{
"node": "Success Notification",
"type": "main",
"index": 0
}
],
[
{
"node": "Failure Notification",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"errorWorkflow": "centralized-error-notification"
},
"versionId": "1",
"id": "budget-export-main",
"tags": [
{
"name": "budget",
"id": "budget"
},
{
"name": "automation",
"id": "automation"
}
]
}
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.
smtpsshPassword
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Budget Export - Main. Uses ssh, emailSend. Scheduled trigger; 7 nodes.
Source: https://github.com/budcalabrese/homelab/blob/26db456f55e2b4b8434d3ca182a208aa051a0a48/n8n-workflows/budget-export-main.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.
This n8n workflow template is designed to help system administrators and DevOps professionals monitor key resource usage metrics — CPU, RAM, and Disk — on a VPS (Virtual Private Server). The workflow
This workflow automates the routine check for upgradable packages on your Ubuntu server, ensuring you stay updated with the latest software patches and security improvements. By running a daily script
Perfect for content publishing with organic scheduling patterns, social media automation, API systems that need to avoid rate limiting, or any automation requiring randomised timing control across mul
Complete backup solution that saves both workflows and credentials to local/server disk with optional FTP upload for off-site redundancy.