SQL
datetime
default value
NOW function
database design

Set NOW as Default Value for datetime datatype?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Using the current timestamp as a column default is a standard database design pattern for audit fields such as created_at. The important detail is that the exact syntax depends on the database engine, and in many systems CURRENT_TIMESTAMP is the portable choice while NOW() is a function with more limited default-value support.

Use the Database Default, Not Application Time

If the goal is "store the insertion time automatically," the database should usually assign that value itself. That keeps the rule centralized and avoids differences between application servers, client clocks, and time zone settings.

A common MySQL example looks like this:

sql
1CREATE TABLE events (
2    id INT PRIMARY KEY AUTO_INCREMENT,
3    description VARCHAR(255) NOT NULL,
4    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
5);
6
7INSERT INTO events (description)
8VALUES ('server started');
9
10SELECT id, description, created_at
11FROM events;

When you omit created_at during the INSERT, the database fills it with the current timestamp. That is more reliable than having every caller remember to pass NOW() manually.

NOW() Versus CURRENT_TIMESTAMP

Developers often ask specifically about NOW(), but the better mental model is: use the expression your database allows in a default clause. In many engines, CURRENT_TIMESTAMP is the standard form.

For MySQL and MariaDB, both NOW() and CURRENT_TIMESTAMP are related, but CURRENT_TIMESTAMP is the usual default expression.

For PostgreSQL, this is idiomatic:

sql
1CREATE TABLE audit_log (
2    id BIGSERIAL PRIMARY KEY,
3    message TEXT NOT NULL,
4    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
5);

For SQL Server, the corresponding idea uses GETDATE() or SYSDATETIME() in a default constraint:

sql
1CREATE TABLE AuditLog (
2    Id INT IDENTITY PRIMARY KEY,
3    Message NVARCHAR(200) NOT NULL,
4    CreatedAt DATETIME2 NOT NULL DEFAULT SYSDATETIME()
5);

So the correct answer is engine-specific. If you ask for NOW() generically, you may end up with syntax that works in one database and fails in another.

Choosing Between DATETIME and TIMESTAMP

The next design question is whether the column should be DATETIME or TIMESTAMP. Different databases implement those types differently, but the practical distinction is usually about time zone handling and semantic intent.

Use a plain date-time type when you want to store a wall-clock value exactly as written. Use a timestamp type when you want a true moment in time that can be interpreted consistently across systems.

For audit columns such as creation time, a timestamp-style type is often the better fit. For scheduled local business times such as "store opens at 09:00," a plain date-time can be more appropriate.

In application code, the insert stays simple because the database handles the default:

python
1import sqlite3
2
3conn = sqlite3.connect(":memory:")
4conn.execute("""
5    CREATE TABLE notes (
6        id INTEGER PRIMARY KEY,
7        body TEXT NOT NULL,
8        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
9    )
10""")
11conn.execute("INSERT INTO notes (body) VALUES (?)", ("first note",))
12for row in conn.execute("SELECT id, body, created_at FROM notes"):
13    print(row)
14conn.close()

This example uses SQLite syntax, but the principle is the same: let the database assign the timestamp unless there is a strong reason not to.

Handling Update Timestamps Separately

A creation default solves only one half of the audit problem. If you also need a modification time, do not assume the insert default will update automatically.

In MySQL, a column can be configured with ON UPDATE CURRENT_TIMESTAMP. In PostgreSQL and SQL Server, you usually use a trigger or update the column explicitly from application code. Keep creation and modification rules separate so the schema reflects the intended behavior clearly.

Common Pitfalls

One common mistake is using NOW() in the INSERT statement everywhere instead of declaring a default. That duplicates logic across the codebase and makes bulk imports, admin tools, and future services easier to get wrong.

Another issue is assuming all databases accept the same default syntax. CURRENT_TIMESTAMP, NOW(), GETDATE(), and SYSDATETIME() are related ideas, but they are not interchangeable.

Time zone handling is another frequent source of bugs. If your application spans regions, decide whether timestamps are stored in UTC, local server time, or a zone-aware type. Make that decision explicitly rather than relying on defaults you have not reviewed.

Finally, do not use a date-time default to hide missing domain logic. A creation timestamp is useful metadata, but business events may need their own separate time columns with different semantics.

Summary

  • For automatic insert times, define the default in the database instead of in application code.
  • 'CURRENT_TIMESTAMP is usually the safest portable concept, while exact syntax depends on the engine.'
  • Choose DATETIME or TIMESTAMP based on time zone behavior and business meaning.
  • Treat creation time and update time as separate design decisions.
  • Review database-specific rules before assuming NOW() is valid in a default clause.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design