• Schedule monthly asset expiry reminders using a built-in Cron trigger instead of maintaining custom scripts or server jobs.
  • Query your existing PostgreSQL database, ToolJetDB, or Google Sheets to automatically detect assets expiring within the next 30 days.
  • Generate email notifications for HR or IT teams using visual workflow nodes and SMTP integrations.
  • Extend your workflow with Slack alerts, Microsoft Teams notifications, approval flows, or owner-specific reminder emails.
  • Deploy the solution on your own infrastructure with ToolJet’s self-hosted workflow automation for greater security, governance, and scalability.

In less than 30 minutes, you can build a working asset expiration reminder app using ToolJet Workflows, without hiring a developer, deploying a backend service, or maintaining a script somewhere. This guide builds a real one, step by step: an internal asset tracker that emails HR every month with a list of equipment (laptops, monitors, licenses) whose warranty or lease is expiring in the next 30 days.

If you already keep a spreadsheet or database of company assets and you’re tired of manually checking expiry dates, this is the exact system to copy. No coding background is required, though a little comfort with spreadsheets and forms will help.

A quick note on jargon: this tutorial uses a few technical words, like SQL, cron, SMTP, and node, because that’s the vocabulary the tool itself uses on-screen. Each one is explained in plain language the first time it shows up, so don’t worry if none of them are familiar yet.

Overview: What you’ll build

Think of the finished system as three connected pieces, like a small assembly line:

  • Asset data source. This is just “where your asset list lives.” It could be a spreadsheet-like database inside ToolJet, an external database, or Google Sheets. It holds one row per asset, with an expiry date and who owns it.
  • ToolJet Workflow. A visual, drag-and-connect pipeline (no code editor required to build the shape of it) that wakes up on a schedule, checks the asset list for anything expiring soon, writes a summary, and sends it.
  • Email provider. The service that actually delivers the email, the same way Gmail or Outlook does. ToolJet just hands the finished message to it.

Building AI-powered workflows without vendor lock-in? ToolJet’s workflow builder handles multi-step agent tasks on your own infrastructure. Check the docs before committing to a SaaS-locked platform.

  •   -> getExpiringAssets   (check the database for assets expiring in 30 days)
  •   -> draftExpiryEmail      (write the subject and body of the email)

Because every piece here is a visual box (“node”) in ToolJet Workflows rather than a piece of custom software, there’s nothing to install, host, or keep running in the background. ToolJet’s own scheduler handles “when this runs,” and each node handles one small piece of “what happens.”

Prerequisites

  • A ToolJet instance (cloud or self-hosted) with Workflows enabled.
  • An asset data source with fields for name, owner, expiry date, and owner email. A spreadsheet with these columns already counts.
  • Access to an email-sending service (this is the “SMTP or transactional email provider,” more on what that means in Step 5).
  • No coding experience is required to follow along; the two places with anything resembling code (a database query and a short formatting script) are given to you in full and explained line by line.

Evaluating Appsmith vs ToolJet for enterprise governance? See how both platforms handle audit logs and RBAC before you commit to a self-hosting strategy.

Step 1: Model your asset data

Define required fields

Before touching ToolJet at all, it helps to know exactly what information you’re working with, what a developer would call your data’s “schema,” which just means the list of columns and what kind of value goes in each one. This tutorial’s asset tracker uses two tables (think: two tabs in a spreadsheet):

assets, one row per physical or software asset:

Column Type Notes
id integer A unique number identifying the row
name text Asset name
asset_type text Laptop, monitor, license, etc.
brand / model text
serial_number text
warranty_expiry date The field this entire workflow revolves around
ownership_type text Owned, leased, etc.
assigned_to integer Points to the matching row in the employees table

employees, one row per staff member an asset can be assigned to:

Column Type Notes
id integer A unique number identifying the row
name text
employee_id text Internal employee code
email text Where reminders ultimately trace back to
department text

One detail worth getting right early: keep warranty_expiry stored as an actual date, not free text like “July 8th” typed by hand. Dates stored properly let the computer do date math (“is this within 30 days?”) automatically, and the query in Step 3 depends on it.

Create or connect your data source

You have two practical options, and neither requires writing software:

  • Option A: ToolJetDB. This is ToolJet’s own built-in database, which behaves a lot like a spreadsheet with stricter columns. Create the assets and employees tables directly inside it. Fastest to set up, nothing extra to host.
  • Option B: an existing database, or Google Sheets. If your asset list already lives somewhere, connect it as a data source instead of copying it into something new.

This tutorial uses an external Postgres database (a common, free, open-source type of database) connected as a ToolJet data source:

  1. Go to Data sources in the left sidebar, then Add data source, then PostgreSQL.
  2. Enter your Host, Port, Database, Username, and Password. Your database administrator or hosting provider gives you these; they’re just the “address and login” for the database.

Fig 1: Adding a Postgres data source in ToolJet

  1. Testing the connection now confirms your credentials and network settings are correct, so you don’t end up debugging workflow issues that are actually connection problems. You should see a “Test connection verified” confirmation. This is ToolJet trying to actually log in with what you typed, right there on the spot, so you find out about a typo immediately instead of later.
  2. Saving the data source now makes it available to every workflow, so you only configure the connection once.

Common mistake: Storing expiry dates as text instead of proper date values. SQL date comparisons rely on native date types to filter assets accurately.

Step 2: Create the ToolJet Workflow

Create a new workflow

Open the Workflows module from the left rail, click Create new workflow, and give it a name (asset-tracker workflow in this example). Every new workflow starts with a single Start node, which you can think of as the “on” button you can click yourself while you’re still testing.

Every workflow starts with a single Start node. Giving the workflow a descriptive name makes it much easier to identify later when you have multiple scheduled automations running in production.

Configure the trigger

A trigger is simply “the thing that kicks the workflow off.” Click the lightning-bolt Triggers icon, expand Schedules, and click New schedule. You’ll see two tabs, Interval and Cron, plus a Timezone field that applies to whichever one you pick.

Interval is the plain-English option: “run this every hour,” “every day,” “every month.” Simple, but it can’t pin an exact calendar date; if you enable an “every month” schedule on the 14th, it keeps firing on the 14th.

For a job that must land on a specific date, like “the 1st of every month,” switch to Cron instead. Cron is an older, more precise scheduling format that uses five separate fields instead of a single dropdown:

How to Build an Asset Expiry Reminder System with ToolJet Workflows (Monthly Email Alerts)

 Fig 2: The Cron schedule option, configured to run monthly

As you fill these in, ToolJet shows a live plain-English confirmation, “Set to run At 09:00 AM, on day 1 of the month,” at the bottom of the panel. You don’t have to be a cron expert to use this: just read that sentence back and check it says what you meant. Treat it as your source of truth.

Step 3: Fetch assets that are about to expire

Add a database query node

A query is just a question you ask the database, like “give me every asset expiring soon.” A node is one visual box in the workflow that does one job. Add a database query node connected after Start, name it getExpiringAssets, point it at your Postgres data source, and switch to SQL mode so you can type the exact question:

SELECT

  a.id,

  a.name,

  a.asset_type,

  a.brand,

  a.model,

  a.serial_number,

  a.warranty_expiry,

  a.ownership_type,

  e.name AS assigned_to,

  e.employee_id AS assigned_employee_id,

  e.email AS assigned_email,

  e.department,

  (a.warranty_expiry – CURRENT_DATE) AS days_until_expiry

FROM assets a

LEFT JOIN employees e ON a.assigned_to = e.id

WHERE a.warranty_expiry IS NOT NULL

AND a.warranty_expiry BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL ’30 days’

ORDER BY a.warranty_expiry ASC;

Fig 3: The getExpiringAssets query node

You don’t need to memorize this; you can copy it as-is and adjust the table and column names to match yours. In plain English, it says: “Get every asset that has a warranty expiry date, where that date falls between today and 30 days from now, and include who it’s assigned to.” The CURRENT_DATE part means “today, whenever this actually runs,” rather than a date typed in by hand, which is exactly what makes this safe to run automatically every month without editing it.

Previewing the query validates your table names, joins, and date filters before the workflow runs automatically each month.

Step 4: Build the email content

Decide email strategy

Two common approaches, and you can pick either without changing anything else in this guide:

  • Single digest email. One email, sent to an admin, IT, or HR distribution list, listing every expiring asset together. Simple, low email volume, the good default for most teams.
  • Per-owner email. Each asset owner gets their own, shorter email listing only their equipment. Better for large fleets with many owners, but takes one more step to set up (see below).

This tutorial builds the digest version, since a single monthly HR summary is the more common request, but the note below shows exactly what changes if you’d rather send one email per owner.

Use a Loop node (if sending multiple emails)

“A Loop node keeps the workflow scalable. Instead of duplicating email logic for every owner, the same steps are reused for each record automatically.” 

If you want per-owner emails instead of one digest, add a Loop node after getExpiringAssets. A loop simply means “repeat these next steps once for each item in a list,” in this case, once per owner. Put the formatting and sending nodes inside the loop so each owner gets their own message. For a single digest email, what we’re building in this tutorial, skip the loop node entirely and connect the query node straight into the formatting node below.

Template the email body

Add a Run JavaScript node connected after the query node, named draftExpiryEmail. This is the step that turns the raw list of assets from Step 3 into an actual, readable paragraph of text, the kind of thing you’d want to read in an email, not a spreadsheet dump.

Here’s the one detail that trips people up, technical or not: how does this step actually get access to the list of assets from the previous step? In ToolJet Workflows, each node’s result is available to later nodes under its own name, so the results from the getExpiringAssets node are available as getExpiringAssets.data. You don’t need to remember this by heart: start typing in the code box, and ToolJet’s autocomplete will suggest it for you, along with every other node currently available.

const expiring = getExpiringAssets.data;

const rows = expiring.map(a =>

  `${a.name} (${a.serial_number}), expires ${a.warranty_expiry}, assigned to ${a.assigned_to} (${a.assigned_employee_id}) <${a.assigned_email}>`

).join(‘\n’);

const body = `Hi HR Team,\n\nThe following assets are expiring within the next 30 days:\n\n${rows}\n\nPlease take necessary action.\n\nIT Asset Tracker`;

return { subject: ‘Assets Expiring in 30 Days’, body };

 

Fig 4: The draftExpiryEmail node, returning a subject and body

You can copy this code directly and just adjust the wording to match your tone. In plain terms: it takes each asset and turns it into one readable line, joins all the lines into one block of text, then wraps that block in a friendly opening and closing line. The very last line, return { subject, body }, is what hands the finished subject line and email body over to the next step.

Keep the subject line short and specific, and put the most useful information (asset name and expiry date) at the start of each line, rather than burying it after the owner’s details.

Step 5: Connect an email provider and send the email

Configure email node

“SMTP” is just the technical name for the standard way computers send email. You don’t need to understand how it works internally, only that it’s the setting your email provider (Gmail, Outlook, Amazon SES, SendGrid, or a free testing service like Mailtrap) gives you to plug in here.

Add an SMTP node connected after the JavaScript node, and pick (or create) an SMTP data source under Data sources, then Add data source, then SMTP.

Fig 5: Adding an SMTP data source

Click Test connection to confirm ToolJet can log into your email provider before you try sending anything for real. Verifying the SMTP connection first isolates authentication issues before you begin troubleshooting the workflow itself.This step alone doesn’t send an email, it just proves the login details work.

Map fields

Back in the workflow, fill in the SMTP node’s fields. This is the equivalent of filling out the “To,” “Subject,” and “Body” boxes when you compose an email by hand:

 

Fig 6: Mapping the sendEmail node’s fields

Field Value
From / From Name Your sender identity
To HR team’s address (or the admin distribution list)
Subject {{draftExpiryEmail.data.subject}}
Text {{draftExpiryEmail.data.body}}

Those double-curly-brace values look unusual, but they mean something simple: “put whatever came out of the draftExpiryEmail step right here.” You’re not retyping the subject and body, you’re pointing at what Step 4 already produced.

A real test email verifies both the SMTP configuration and the final formatting, which is something execution logs alone can’t confirm:

With all nodes wired up, the canvas looks like this:

 Fig 7: The complete workflow canvas

Handle failures

For a version of this workflow you plan to rely on long-term, it’s worth adding an If-condition node right after the SMTP node. This checks “did the email actually send successfully?” and, if not, does something about it instead of failing silently. That could be a Slack message, a note added to a log, or a backup email to your IT team. This tutorial skips that extra branch to keep the main pipeline easy to follow the first time through, but it’s a good next addition once the basics are working.

Step 6: Test, debug, and schedule

Dry-run with test data

Before turning anything on automatically, click Run (or Run Workflow from inside any node) to walk through the full chain by hand: Start, then getExpiringAssets, then draftExpiryEmail, then sendEmail, using your real data, or a small handful of test rows if you’d rather not send a real email to HR yet.

Validate output

Check the Logs tab at the bottom of the builder. This is a plain, timestamped list showing whether each step succeeded or failed, so you don’t have to guess:

 Fig 8: Execution logs confirming each node succeeded

Then confirm the email actually arrived, and reads the way you intended:

 

Fig 9: The finished reminder email, received in Gmail

This last check matters more than it might seem. Each individual step can report “success” while something small in the wording or formatting still looks off. Reading the actual email in an inbox is the only way to be sure everything lines up the way a real recipient will see it.

Comparing total cost of ownership across platforms? See where enterprise tooling costs stack up beyond sticker price. Seat structures, compliance overhead, and migration effort all add up faster than the per-seat number suggests.

Turn on the schedule

Once the test run looks right, go back to the schedule you set up in Step 2 and flip two switches. Only enable the schedule after a successful manual run. This prevents recurring failures from running automatically every month:

  1. The schedule’s own toggle, next to its plain-English description (e.g. “At 09:00 AM, on day 1 of the month”)
  2. The workflow-level Enable toggle in the top right, the master on/off switch for the whole workflow

 

Fig 10: The schedule and workflow both switched on

Once both are switched on, ToolJet takes over entirely. You don’t need to keep a computer running, remember to click anything, or check back in except to glance at the Logs tab occasionally to confirm past runs went smoothly.

Wrapping up

That’s the complete pipeline: a handful of connected steps, one schedule, and nothing extra to maintain:

Cron (1st of month, 9 AM)

  -> getExpiringAssets   (check the database for assets expiring in 30 days)

  -> draftExpiryEmail      (write the subject and body of the email)

  -> sendEmail             (deliver it to HR)

Optional: Extend the asset reminder system

Once the core version works, here are a few natural next additions. None of them require rebuilding what you already have:

  • Add a simple ToolJet app where staff can view and update their own assigned assets, instead of only receiving a read-only email.
  • Add Slack or Microsoft Teams notifications alongside (or instead of) email, by connecting the same first two steps to a different final “send” step.
  • Add a follow-up reminder, a second scheduled workflow that checks a week later for anything still unresolved.
  • Add filters for department or location, so different teams only see the assets relevant to them.

Need governance features without an enterprise sales cycle? See what ToolJet’s audit logs cover on paid plans before finalizing your shortlist.

A few things worth remembering, whether or not you come from a technical background:

Check an actual inbox, not just a green checkmark, before turning the schedule on for real.”

Each step’s results are available to later steps under its own name, as nodeName.data. Let ToolJet’s autocomplete suggest the exact wording if you’re ever unsure.

Test every connection before you build on it. A “Test connection verified” on both your database and your email provider, done up front, saves a lot of confusion later.

Trust the plain-English confirmation under the Cron schedule over your own reading of the five fields; it’s there specifically so you don’t have to become a scheduling expert.

Check an actual inbox, not just a green checkmark, before turning the schedule on for real.

“A few things worth remembering, whether or not you come from a technical background:

  • Each step’s results are available to later steps under its own name, as nodeName.data. Let ToolJet’s autocomplete suggest the exact wording if you’re ever unsure.
  • Test every connection before you build on it. A “Test connection verified” on both your database and your email provider, done up front, saves a lot of confusion later.
  • Trust the plain-English confirmation under the Cron schedule over your own reading of the five fields; it’s there specifically so you don’t have to become a scheduling expert.
  • Check an actual inbox, not just a green checkmark, before turning the schedule on for real.”

From here, the same shape (schedule, check the list, format, notify) works just as well for license renewals, contract expirations, or anything else you’re currently tracking by memory in a spreadsheet.

Shortlisting platforms for an enterprise rollout? Run through the enterprise readiness checklist before you lock in a vendor. It covers governance, deployment, and AI readiness in one pass.

Why ToolJet is the fastest way to build asset reminders

Asset reminders shouldn’t need a backend team or a fragile cron file. That’s the whole point. With ToolJet Workflows, you model your data, set a monthly trigger, filter expiring assets, and email  owners, all on one visual canvas. It runs server-side, self-hosts on your own infrastructure, and  scales as your asset list grows. No per-end-user charges, open source under AGPL v3, and SOC 2  alignment when governance matters. So yeah, you ship a production-ready reminder system today, not  next quarter. Then extend it into a full asset platform whenever you’re ready.