Pulumi Any Terraform

Static Resource

Capture a static timestamp at resource creation time

The time.Static resource captures a timestamp when the resource is created and keeps it unchanged until the resource is recreated.

Example Usage

Basic Timestamp

import * as pulumi from "@pulumi/pulumi";
import * as time from "@pulumi/time";

// Capture creation timestamp
const timestamp = new time.Static("creation-time", {});

export const createdAt = timestamp.rfc3339;

With Triggers

const config = new pulumi.Config();
const version = config.require("version");

const deploymentTime = new time.Static("deployment-time", {
    triggers: {
        version: version, // New timestamp when version changes
    },
});

export const deploymentInfo = {
    version: version,
    deployedAt: deploymentTime.rfc3339,
};

Resource Tagging

import * as aws from "@pulumi/aws";
import * as time from "@pulumi/time";

const createdAt = new time.Static("creation-time", {});

const instance = new aws.ec2.Instance("server", {
    // ... configuration
    tags: {
        Name: "web-server",
        CreatedAt: createdAt.rfc3339,
        CreatedUnix: createdAt.unix.apply(u => u.toString()),
    },
});

Argument Reference

Optional Arguments

  • rfc3339 (string): Base timestamp in RFC3339 format. Defaults to current time.
  • triggers (map): Arbitrary map that causes new timestamp when values change.

Attribute Reference

  • day (number): Day of the timestamp (1-31).
  • hour (number): Hour of the timestamp (0-23).
  • id (string): Unique identifier (same as unix timestamp).
  • minute (number): Minute of the timestamp (0-59).
  • month (number): Month of the timestamp (1-12).
  • rfc3339 (string): Timestamp in RFC3339 format.
  • second (number): Second of the timestamp (0-59).
  • unix (number): Unix timestamp (seconds since epoch).
  • year (number): Year of the timestamp.

Use Cases

Deployment Tracking

import * as time from "@pulumi/time";

const deploymentTimestamp = new time.Static("deployment-timestamp", {});

export const deploymentMetadata = {
    timestamp: deploymentTimestamp.rfc3339,
    unix: deploymentTimestamp.unix,
    readable: deploymentTimestamp.rfc3339.apply(t => 
        new Date(t).toLocaleString()
    ),
};

Resource Lifecycle Tracking

import * as aws from "@pulumi/aws";
import * as time from "@pulumi/time";

const resourceCreated = new time.Static("resource-created", {});

const bucket = new aws.s3.Bucket("data", {
    bucket: "my-bucket",
    tags: {
        CreatedAt: resourceCreated.rfc3339,
        CreatedBy: "pulumi",
        Environment: "production",
    },
});

export const bucketMetadata = {
    name: bucket.bucket,
    createdAt: resourceCreated.rfc3339,
};

Version Tracking

import * as pulumi from "@pulumi/pulumi";
import * as time from "@pulumi/time";

const config = new pulumi.Config();
const appVersion = config.require("appVersion");

const versionTimestamp = new time.Static("version-timestamp", {
    triggers: {
        version: appVersion,
    },
});

export const versionInfo = {
    version: appVersion,
    deployedAt: versionTimestamp.rfc3339,
    deployedUnix: versionTimestamp.unix,
};

Audit Trail

import * as time from "@pulumi/time";

const stackCreated = new time.Static("stack-created", {});

const auditInfo = {
    stackName: pulumi.getStack(),
    projectName: pulumi.getProject(),
    createdAt: stackCreated.rfc3339,
    createdUnix: stackCreated.unix,
};

export const auditTrail = auditInfo;

Configuration Snapshot

import * as pulumi from "@pulumi/pulumi";
import * as time from "@pulumi/time";

const config = new pulumi.Config();
const configHash = config.require("configHash");

const configTimestamp = new time.Static("config-timestamp", {
    triggers: {
        configHash: configHash, // New timestamp when config changes
    },
});

export const configSnapshot = {
    hash: configHash,
    updatedAt: configTimestamp.rfc3339,
    updatedUnix: configTimestamp.unix,
};

Comparison with Other Time Resources

ResourceBehaviorUse Case
StaticCaptures timestamp once, unchangingCreation time tracking
OffsetCalculates future/past timeExpiration dates
RotatingChanges on scheduleAutomatic rotation triggers
SleepAdds delaysWaiting for resources

Example: Complete Metadata System

import * as pulumi from "@pulumi/pulumi";
import * as time from "@pulumi/time";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();
const appVersion = config.require("version");
const environment = config.require("environment");

// Capture deployment time
const deployedAt = new time.Static("deployed-at", {
    triggers: {
        version: appVersion,
        environment: environment,
    },
});

// Calculate expiration (90 days for dev, never for prod)
const expiresAt = new time.Offset("expires-at", {
    baseRfc3339: deployedAt.rfc3339,
    offsetDays: environment === "dev" ? 90 : 36500, // 100 years = "never"
});

// Create resources with metadata
const instance = new aws.ec2.Instance("app-server", {
    instanceType: "t3.micro",
    tags: {
        Name: `app-${environment}`,
        Version: appVersion,
        Environment: environment,
        DeployedAt: deployedAt.rfc3339,
        ExpiresAt: expiresAt.rfc3339,
        ManagedBy: "pulumi",
    },
});

export const metadata = {
    version: appVersion,
    environment: environment,
    deployedAt: deployedAt.rfc3339,
    expiresAt: expiresAt.rfc3339,
    instanceId: instance.id,
};

Best Practices

Use for Immutable Timestamps

// ✅ Good: Capture creation time
const created = new time.Static("created", {});

// ❌ Bad: Use Rotating for changing timestamps
// const changing = new time.Static("changing", {});

Combine with Triggers

// ✅ Good: Update timestamp on meaningful changes
const deployed = new time.Static("deployed", {
    triggers: {
        version: appVersion,
        config: configHash,
    },
});

// ❌ Bad: Random triggers
const timestamp = new time.Static("timestamp", {
    triggers: {
        random: Math.random().toString(),
    },
});

Export for Visibility

const timestamp = new time.Static("timestamp", {});

// ✅ Good: Export for tracking
export const creationTime = timestamp.rfc3339;
export const creationUnix = timestamp.unix;

Import

Time static resources cannot be imported as they represent point-in-time captures rather than existing infrastructure.

Notes

  • Timestamp is captured at resource creation
  • Unchanging unless resource is recreated
  • Use triggers to force new timestamp
  • All times are in UTC
  • Useful for audit trails and metadata