How are Shiny submodule servers namespaced?

When nesting Shiny modules the UI functions for a sub-module must use the NS() function from the containing Shiny module. This makes more sense to me now that I've realized this, but before I realized this I was confused why my submodule wasn't communicating properly with it's server (I should've suspected namespacing sooner, and I did; in fact I tried using session$NS to namespace the sub-module first [which didn't work]).

I know I am rambling; I might not make sense yet.

In short, how are sub-modules (modules within modules) namespaced, other than the id argument passed to their module server-returning function?

Hi @bryce-carson

i will try an explanation (the Chapter 19 Shiny modules | Mastering Shiny is worth reading, i used the example from there and adapted it)

Given the following code

library(shiny)

# https://mastering-shiny.org/scaling-modules.html 19.2.1 Module UI
histogramUI <- function(id) {
  tagList(
    selectInput(NS(id, "var"), "Variable", choices = names(mtcars)),
    numericInput(NS(id, "bins"), "bins", value = 10, min = 1),
    plotOutput(NS(id, "hist"))
  )
}

outerUI <- function(id) {
  tagList(
    histogramUI(NS(id, "nested"))
  )
}


# https://mastering-shiny.org/scaling-modules.html 19.2.2 Module server
histogramServer <- function(id) {
  moduleServer(id, function(input, output, session) {
    data <- reactive(mtcars[[input$var]])
    output$hist <- renderPlot({
      hist(data(), breaks = input$bins, main = input$var)
    }, res = 96)
  })
}

outerServer <- function(id) {
  moduleServer(id, function(input, output, session) {
    histogramServer("nested")
  })
}

# https://mastering-shiny.org/scaling-modules.html 19.2.3 Updated app (adapted)
ui <- fluidPage(
  outerUI("main")
)
server <- function(input, output, session) {
  outerServer("main")
}
shinyApp(ui, server)  

In the UI case an explicit NS() is necessary. histogramUI(NS(id, "nested")) inside of outerUI will result in every object of histogramUI getting the prefix main-nested-"name of variable".

In the server case an explicit sessions$ns is NOT necessary to call. The moduleServer will prepend the necessary id to the nested module and the name spacing will match what you expect.

In the example above i call outerServer("main") which contains histogramServer("nested"). There is no explicit call to session$ns in neither module. outerServer("main") + histogramServer("nested") will end up prepending main-nested to every object of histogramServer. So the output$hist inside the histogramServer will be name spaced as main-nested-hist matching the ui object main-nested-hist.

Hope it gives somewhat of an explanation.