or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-management.mdautomation.mdconfiguration.mddynamic-resources.mdindex.mdlogging-diagnostics.mdoutput-system.mdprovider-development.mdresource-management.mdruntime-operations.mdstack-references.mdutilities.md

asset-management.mddocs/

0

# Asset Management

1

2

Pulumi's asset system enables packaging and deployment of files, directories, and remote content as part of your infrastructure resources, commonly used for Lambda functions, container images, and configuration files.

3

4

## Core Asset Classes

5

6

```typescript { .api }

7

abstract class Asset {

8

readonly __pulumiAsset: boolean;

9

}

10

11

abstract class Archive {

12

readonly __pulumiArchive: boolean;

13

}

14

15

// File-based assets

16

class FileAsset extends Asset {

17

constructor(path: string);

18

readonly path: string;

19

}

20

21

class StringAsset extends Asset {

22

constructor(text: string);

23

readonly text: string;

24

}

25

26

class RemoteAsset extends Asset {

27

constructor(uri: string);

28

readonly uri: string;

29

}

30

31

// Archive types

32

class FileArchive extends Archive {

33

constructor(path: string);

34

readonly path: string;

35

}

36

37

class AssetArchive extends Archive {

38

constructor(assets: AssetMap);

39

readonly assets: AssetMap;

40

}

41

42

class RemoteArchive extends Archive {

43

constructor(uri: string);

44

readonly uri: string;

45

}

46

47

type AssetMap = {[name: string]: Asset | Archive};

48

```

49

50

## Usage Examples

51

52

### File Assets

53

54

```typescript

55

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

56

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

57

58

// Single file asset

59

const configFile = new pulumi.asset.FileAsset("./config/app.json");

60

61

// Use in S3 bucket object

62

const configObject = new aws.s3.BucketObject("app-config", {

63

bucket: bucket.id,

64

key: "config/app.json",

65

source: configFile,

66

contentType: "application/json",

67

});

68

69

// String-based asset for generated content

70

const indexHtml = new pulumi.asset.StringAsset(`

71

<!DOCTYPE html>

72

<html>

73

<head>

74

<title>My App</title>

75

</head>

76

<body>

77

<h1>Welcome to My App</h1>

78

<p>Environment: ${config.require("environment")}</p>

79

</body>

80

</html>

81

`);

82

83

const indexObject = new aws.s3.BucketObject("index", {

84

bucket: bucket.id,

85

key: "index.html",

86

source: indexHtml,

87

contentType: "text/html",

88

});

89

```

90

91

### Archive Assets

92

93

```typescript

94

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

95

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

96

97

// Directory archive for Lambda function

98

const lambdaCode = new pulumi.asset.FileArchive("./lambda-function");

99

100

const lambdaFunction = new aws.lambda.Function("my-function", {

101

runtime: "nodejs18.x",

102

code: lambdaCode,

103

handler: "index.handler",

104

role: lambdaRole.arn,

105

});

106

107

// Selective file archive

108

const webAssets = new pulumi.asset.AssetArchive({

109

"index.html": new pulumi.asset.FileAsset("./web/index.html"),

110

"styles.css": new pulumi.asset.FileAsset("./web/styles.css"),

111

"app.js": new pulumi.asset.FileAsset("./web/app.js"),

112

"assets/": new pulumi.asset.FileArchive("./web/assets"),

113

});

114

115

const websiteZip = new aws.s3.BucketObject("website", {

116

bucket: bucket.id,

117

key: "website.zip",

118

source: webAssets,

119

});

120

```

121

122

### Remote Assets

123

124

```typescript

125

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

126

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

127

128

// Remote file asset

129

const remoteScript = new pulumi.asset.RemoteAsset(

130

"https://raw.githubusercontent.com/myorg/scripts/main/setup.sh"

131

);

132

133

// Remote archive

134

const applicationCode = new pulumi.asset.RemoteArchive(

135

"https://github.com/myorg/myapp/archive/v1.2.3.tar.gz"

136

);

137

138

const lambdaFromRemote = new aws.lambda.Function("remote-function", {

139

runtime: "python3.9",

140

code: applicationCode,

141

handler: "main.handler",

142

role: lambdaRole.arn,

143

});

144

```

145

146

### Dynamic Asset Generation

147

148

```typescript

149

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

150

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

151

import * as fs from "fs";

152

import * as path from "path";

153

154

// Generate configuration file dynamically

155

const config = new pulumi.Config();

156

const environment = config.require("environment");

157

158

const appConfig = {

159

environment: environment,

160

apiEndpoint: config.require("apiEndpoint"),

161

features: {

162

authentication: config.getBoolean("enableAuth") || false,

163

analytics: config.getBoolean("enableAnalytics") || false,

164

},

165

buildTimestamp: new Date().toISOString(),

166

};

167

168

const configAsset = new pulumi.asset.StringAsset(

169

JSON.stringify(appConfig, null, 2)

170

);

171

172

// Create archive with generated content

173

const deploymentPackage = new pulumi.asset.AssetArchive({

174

"config.json": configAsset,

175

"app/": new pulumi.asset.FileArchive("./src"),

176

"package.json": new pulumi.asset.FileAsset("./package.json"),

177

"yarn.lock": new pulumi.asset.FileAsset("./yarn.lock"),

178

});

179

```

180

181

### Container Image Assets

182

183

```typescript

184

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

185

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

186

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

187

188

// Build and push container image

189

const repository = new aws.ecr.Repository("app-repo");

190

191

const image = new docker.Image("app-image", {

192

build: {

193

context: "./app",

194

dockerfile: "./app/Dockerfile",

195

},

196

imageName: pulumi.interpolate`${repository.repositoryUrl}:latest`,

197

registry: {

198

server: repository.repositoryUrl,

199

username: "AWS",

200

password: pulumi.output(aws.ecr.getAuthorizationToken({

201

registryId: repository.registryId,

202

})).authorizationToken.apply(token =>

203

Buffer.from(token, "base64").toString().split(":")[1]

204

),

205

},

206

});

207

208

// Use in ECS task definition

209

const taskDefinition = new aws.ecs.TaskDefinition("app-task", {

210

family: "my-app",

211

containerDefinitions: pulumi.jsonStringify([{

212

name: "app",

213

image: image.imageName,

214

memory: 512,

215

essential: true,

216

portMappings: [{

217

containerPort: 8080,

218

hostPort: 8080,

219

}],

220

}]),

221

});

222

```

223

224

### Asset Transformation Patterns

225

226

```typescript

227

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

228

import * as fs from "fs";

229

import * as path from "path";

230

231

// Template processing function

232

function processTemplate(templatePath: string, variables: Record<string, any>): pulumi.asset.StringAsset {

233

let template = fs.readFileSync(templatePath, "utf8");

234

235

Object.entries(variables).forEach(([key, value]) => {

236

const placeholder = new RegExp(`{{\\s*${key}\\s*}}`, "g");

237

template = template.replace(placeholder, String(value));

238

});

239

240

return new pulumi.asset.StringAsset(template);

241

}

242

243

// Use template processing

244

const config = new pulumi.Config();

245

const nginxConfig = processTemplate("./templates/nginx.conf.template", {

246

serverName: config.require("serverName"),

247

upstreamHost: config.require("upstreamHost"),

248

upstreamPort: config.getNumber("upstreamPort") || 8080,

249

});

250

251

// Bundle multiple processed templates

252

const configBundle = new pulumi.asset.AssetArchive({

253

"nginx.conf": nginxConfig,

254

"mime.types": new pulumi.asset.FileAsset("./config/mime.types"),

255

"ssl/": new pulumi.asset.FileArchive("./ssl-certificates"),

256

});

257

```

258

259

### Conditional Assets

260

261

```typescript

262

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

263

264

const config = new pulumi.Config();

265

const environment = config.require("environment");

266

267

// Different assets based on environment

268

function getLambdaCode(): pulumi.asset.Archive {

269

if (environment === "development") {

270

// Use local development build

271

return new pulumi.asset.FileArchive("./dist/dev");

272

} else if (environment === "production") {

273

// Use optimized production build

274

return new pulumi.asset.FileArchive("./dist/prod");

275

} else {

276

// Use pre-built artifact from CI/CD

277

const artifactUrl = config.require("artifactUrl");

278

return new pulumi.asset.RemoteArchive(artifactUrl);

279

}

280

}

281

282

const lambdaFunction = new aws.lambda.Function("app-function", {

283

runtime: "nodejs18.x",

284

code: getLambdaCode(),

285

handler: "index.handler",

286

role: lambdaRole.arn,

287

environment: {

288

variables: {

289

NODE_ENV: environment,

290

},

291

},

292

});

293

```

294

295

### Asset Validation and Helpers

296

297

```typescript

298

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

299

import * as fs from "fs";

300

import * as path from "path";

301

302

// Utility function to validate assets exist

303

function validateAssetPath(assetPath: string): string {

304

const fullPath = path.resolve(assetPath);

305

if (!fs.existsSync(fullPath)) {

306

throw new Error(`Asset path does not exist: ${fullPath}`);

307

}

308

return assetPath;

309

}

310

311

// Helper for creating archives with validation

312

function createValidatedArchive(paths: Record<string, string>): pulumi.asset.AssetArchive {

313

const assets: Record<string, pulumi.asset.Asset | pulumi.asset.Archive> = {};

314

315

Object.entries(paths).forEach(([key, assetPath]) => {

316

validateAssetPath(assetPath);

317

318

const stats = fs.statSync(assetPath);

319

if (stats.isDirectory()) {

320

assets[key] = new pulumi.asset.FileArchive(assetPath);

321

} else {

322

assets[key] = new pulumi.asset.FileAsset(assetPath);

323

}

324

});

325

326

return new pulumi.asset.AssetArchive(assets);

327

}

328

329

// Usage with validation

330

const applicationBundle = createValidatedArchive({

331

"src/": "./src",

332

"package.json": "./package.json",

333

"config.json": "./config/production.json",

334

});

335

```

336

337

## Best Practices

338

339

- Use `FileArchive` for packaging entire directories (Lambda functions, web assets)

340

- Use `StringAsset` for generated configuration files and templates

341

- Validate asset paths exist before creating assets

342

- Use remote assets for artifacts from CI/CD pipelines

343

- Consider asset size limits for target services (e.g., Lambda 50MB limit)

344

- Use appropriate content types for S3 objects

345

- Cache remote assets locally during development when possible

346

- Use consistent directory structures for deployable assets

347

- Include only necessary files in archives to minimize deployment size

348

- Use environment-specific asset selection patterns for different deployment stages