@@ -242,6 +242,220 @@ remote_state = {
242242 different key/value pairs, so consult the [ Terraform remote state docs] ( https://www.terraform.io/docs/state/remote/ )
243243 for details.
244244
245+ ## Managing multiple .terragrunt files
246+
247+ With Terraform, it can be a good idea to store your templates in separate folders (and therefore, separate state files)
248+ to provide isolation between different environments,such as stage and prod, and different components, such as a
249+ database and an app cluster (for more info, see [ How to Manage Terraform
250+ State] ( https://blog.gruntwork.io/how-to-manage-terraform-state-28f5697e68fa ) ). That means you will need a ` .terragrunt `
251+ file in each folder:
252+
253+ ```
254+ my-terraform-repo
255+ └ qa
256+ └ my-app
257+ └ main.tf
258+ └ .terragrunt
259+ └ stage
260+ └ my-app
261+ └ main.tf
262+ └ .terragrunt
263+ └ prod
264+ └ my-app
265+ └ main.tf
266+ └ .terragrunt
267+ ```
268+
269+ Most of these ` .terragrunt ` files will have the almost the same content. For example, ` qa/my-app/.terragrunt ` may look
270+ like this:
271+
272+ ``` hcl
273+ # Configure Terragrunt to use DynamoDB for locking
274+ lock = {
275+ backend = "dynamodb"
276+ config {
277+ state_file_id = "qa/my-app"
278+ }
279+ }
280+
281+ # Configure Terragrunt to automatically store tfstate files in an S3 bucket
282+ remote_state = {
283+ backend = "s3"
284+ config {
285+ encrypt = "true"
286+ bucket = "my-bucket"
287+ key = "qa/my-app/terraform.tfstate"
288+ region = "us-east-1"
289+ }
290+ }
291+ ```
292+
293+ And ` stage/my-app/.terragrunt ` may look like this:
294+
295+ ``` hcl
296+ # Configure Terragrunt to use DynamoDB for locking
297+ lock = {
298+ backend = "dynamodb"
299+ config {
300+ state_file_id = "stage/my-app"
301+ }
302+ }
303+
304+ # Configure Terragrunt to automatically store tfstate files in an S3 bucket
305+ remote_state = {
306+ backend = "s3"
307+ config {
308+ encrypt = "true"
309+ bucket = "my-bucket"
310+ key = "stage/my-app/terraform.tfstate"
311+ region = "us-east-1"
312+ }
313+ }
314+ ```
315+
316+ Note how most of the content is copy/pasted, except for the ` state_file_id ` and ` key ` parameters, which match the path
317+ of the ` .terragrunt ` file itself. How do you avoid having to manually maintain the contents of all of these
318+ similar-looking ` .terragrunt ` files?
319+
320+ The solution is to use the following features of Terragrunt:
321+
322+ * Includes
323+ * Find parent helper
324+ * Relative path helper
325+ * Overriding included settings
326+
327+ ### Includes
328+
329+ One ` .terragrunt ` file can automatically "include" the contents of another ` .terragrunt ` file using the ` include `
330+ block. For example, imagine you have the following file layout:
331+
332+ ```
333+ my-terraform-repo
334+ └ .terragrunt
335+ └ qa
336+ └ my-app
337+ └ main.tf
338+ └ .terragrunt
339+ └ stage
340+ └ my-app
341+ └ main.tf
342+ └ .terragrunt
343+ └ prod
344+ └ my-app
345+ └ main.tf
346+ └ .terragrunt
347+ ```
348+
349+ The ` .terragrunt ` file in the root folder defines the typical ` lock ` and ` remote_state ` settings. The ` .terragrunt `
350+ files in all the subfolders (e.g. ` qa/my-app/.terragrunt ` ) can automatically include all the settings from a parent
351+ file using the ` include ` block:
352+
353+ ``` hcl
354+ include = {
355+ path = "../../.terragrunt"
356+ }
357+ ```
358+
359+ When you run Terragrunt in the ` qa/my-app ` folder, it will see the ` include ` block in the ` qa/my-app/.terragrunt ` file
360+ and realize that it should load the contents of the root ` .terragrunt ` file instead. It's almost as if you had
361+ copy/pasted the contents of the root ` .terragrunt ` file into ` qa/my-app/.terragrunt ` , but much easier to maintain!
362+
363+ ** Note** : only one level of includes is allowed. If ` root/qa/my-app/.terragrunt ` includes ` root/.terragrunt ` , then
364+ ` root/.terragrunt ` may NOT specify an ` include ` block.
365+
366+ There are a few problems with the simple approach above, so read on before using it!
367+
368+ 1 . Having to manually manage the file paths to the included ` .terragrunt ` file is tedious and error prone. To solve
369+ this problem, you can use the ` find_in_parent_folders() ` helper.
370+ 1 . If the included ` .terragrunt ` file hard-codes the ` state_file_id ` and ` key ` settings, then every child that includes
371+ it would end up using the same lock and write state to the same location. To avoid this problem, you can use the
372+ ` path_relative_to_include() ` helper.
373+ 1 . Some of the child ` .terragrunt ` files may want to override the settings they include. To do this, see the section
374+ on overriding included settings.
375+
376+ Each of these items is discussed next.
377+
378+ ### find_in_parent_folders helper
379+
380+ Terragrunt supports the use of a few helper functions using the same syntax as Terraform: ` ${some_function()} ` . One of
381+ the supported helper functions is ` find_in_parent_folders() ` , which returns the path to the first ` .terragrunt ` file it
382+ finds in the parent folders above the current ` .terragrunt ` file.
383+
384+ Example:
385+
386+ ``` hcl
387+ include = {
388+ path = "${find_in_parent_folders()}"
389+ }
390+ ```
391+
392+ If you ran this in ` qa/my-app/.terragrunt ` , this would automatically set ` path ` to ` ../../.terragrunt ` . You will almost
393+ always want to use this function, as it allows you to copy/paste the same ` .terragrunt ` file to all child folders with
394+ no changes.
395+
396+ ` find_in_parent_folders() ` will search up the directory tree until it hits the root folder of your file system, and if
397+ no ` .terragrunt ` file is found, Terragrunt will exit with an error.
398+
399+ ### path_relative_to_include helper
400+
401+ Another helper function supported by Terragrunt is ` path_relative_to_include() ` , which returns the relative path between
402+ the current ` .terragrunt ` file and the path specified in its ` include ` block. For example, in the root ` .terragrunt `
403+ file, you could do the following:
404+
405+ ``` hcl
406+ # Configure Terragrunt to use DynamoDB for locking
407+ lock = {
408+ backend = "dynamodb"
409+ config {
410+ state_file_id = "${path_relative_to_include()}"
411+ }
412+ }
413+
414+ # Configure Terragrunt to automatically store tfstate files in an S3 bucket
415+ remote_state = {
416+ backend = "s3"
417+ config {
418+ encrypt = "true"
419+ bucket = "my-bucket"
420+ key = "${path_relative_to_include()}/terraform.tfstate"
421+ region = "us-east-1"
422+ }
423+ }
424+ ```
425+
426+ Each child ` .terragrunt ` file that references the configuration above in its ` include ` block will get a unique path for
427+ its ` state_file_id ` and ` key ` settings. For example, in ` qa/my-app/.terragrunt ` , the ` state_file_id ` will resolve to
428+ ` qa/my-app ` and the ` key ` will resolve to ` qa/my-app/terraform.tfstate ` .
429+
430+ You will almost always want to use this helper too. The only time you may want to specify the ` state_file_id ` or ` key `
431+ manually is if you moved a child folder. In that case, to ensure it can reuse its old state and lock, you may want to
432+ hard-code the ` state_file_id ` and ` key ` to the old file path. However, a safer approach would be to move the state
433+ files themselves to match the new location of the child folder, as that makes things more consistent!
434+
435+ ### Overriding included settings
436+
437+ Any settings in the child ` .terragrunt ` file will override the settings pulled in via an ` include ` . For example,
438+ imagine if ` qa/my-app/.terragrunt ` had the following contents:
439+
440+ ``` hcl
441+ include = {
442+ path = "${find_in_parent_folders()}"
443+ }
444+
445+ remote_state = {
446+ backend = "s3"
447+ config {
448+ encrypt = "true"
449+ bucket = "some-other-bucket"
450+ key = "/foo/bar/terraform.tfstate"
451+ region = "us-west-2"
452+ }
453+ }
454+ ```
455+
456+ The result is that when you run ` terragrunt ` commands in the ` qa/my-app ` folder, you get the ` lock ` settings from the
457+ parent, but the ` remote_state ` settings of the child.
458+
245459## CLI Options
246460
247461Terragrunt forwards all arguments and options to Terraform. The only exceptions are the options that start with the
0 commit comments