Analysis of Periop Fluids Ped Surgery

Intravenous Fluid Management in the Perioperative Care of Paediatric Patients Undergoing Non-Cardiac Surgery — Scoping Review

Author

JA Calvache

Published

February 1, 2026

Show R code
# ── Global ggplot2 theme ───────────────────────────────────────────────────────
theme_review <- function() {
  theme_minimal(base_size = 12, base_family = "sans") +
    theme(
      plot.title       = element_text(face = "bold", size = 13, hjust = 0),
      plot.subtitle    = element_text(size = 10, colour = "grey40", hjust = 0),
      plot.caption     = element_text(size = 8,  colour = "grey55", hjust = 0),
      axis.title       = element_text(size = 10),
      panel.grid.major.x = element_blank(),
      panel.grid.minor   = element_blank(),
      legend.position    = "bottom",
      legend.title       = element_text(face = "bold", size = 9),
      strip.text         = element_text(face = "bold"),
      plot.background    = element_rect(fill = "white", colour = NA),
      panel.border       = element_blank()
    )
}

# ── Colour palettes ────────────────────────────────────────────────────────────
pal_main <- c("#2E4A8F", "#1F6B8F", "#2E6B50", "#8F5B2E", "#6B2E6B")
pal_seq  <- c("#EBF0FB", "#B8C9EE", "#7A99D9", "#3D6BBF", "#2E4A8F")

Note

Methodological note: This document presents a descriptive narrative synthesis of 55 studies included in the scoping review. All statistics are computed directly from the structured data extraction database (popfluids2.csv). R code is visible via the Show R code toggles. Place popfluids2.csv in your RStudio working directory before rendering.


1 General Characteristics of Included Studies

This narrative synthesis presents a descriptive analysis of the 55 studies included in a scoping review examining intravenous fluid management in the perioperative care of paediatric patients undergoing non-cardiac surgery. The available evidence spans four decades, with publications ranging from 1984 to 2024; approximately 74% of studies were published from 2010 onwards, reflecting a progressively growing interest in standardising and optimising fluid therapy practices in the paediatric surgical setting.

1.1 Study Designs

Show R code
design_tab <- df |>
  filter(!is.na(design_label)) |>
  count(design_label, name = "n") |>
  arrange(desc(n)) |>
  mutate(`%` = percent(n / sum(n), accuracy = 0.1)) |>
  rename(`Study Design` = design_label)

design_tab |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(design_tab), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 1: Distribution of included studies by study design.
Study Design n %
Randomised Controlled Trial 44 80.0%
Cohort Study 9 16.4%
Other Design 2 3.6%

Randomised controlled trials (RCTs) predominated, accounting for 44 of the 55 included studies (80.0%). The preponderance of RCTs represents a methodologically favourable characteristic of the available evidence base; nevertheless, heterogeneity in evaluated outcomes and enrolled populations substantially limits direct cross-study comparability.

Show R code
df |>
  filter(!is.na(design_label)) |>
  count(design_label) |>
  mutate(design_label = fct_reorder(design_label, n)) |>
  ggplot(aes(x = n, y = design_label, fill = design_label)) +
  geom_col(width = 0.6, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({percent(n / n_total, accuracy = 0.1)})")),
            hjust = -0.1, size = 3.5, colour = "grey30") +
  scale_fill_manual(values = pal_main[1:3]) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.22))) +
  labs(x = "Number of studies", y = NULL,
       title = "Study designs across included publications",
       caption = glue("N = {n_total} studies")) +
  theme_review()
Figure 1: Distribution of included studies by study design.

1.3 Geographical Distribution

Show R code
country_tab <- df |>
  filter(!is.na(country_clean)) |>
  count(country_clean, name = "n") |>
  arrange(desc(n)) |>
  mutate(`%` = percent(n / sum(n), accuracy = 0.1)) |>
  rename(Country = country_clean)

country_tab |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(country_tab), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 2: Geographical distribution of included studies.
Country n %
Germany 9 16.4%
China 5 9.1%
India 5 9.1%
South Korea 4 7.3%
USA 4 7.3%
Australia 3 5.5%
Iran 3 5.5%
Suecia 3 5.5%
Brazil 2 3.6%
Nigeria 2 3.6%
Spain 2 3.6%
United Kingdom 2 3.6%
Austria 1 1.8%
Canadá 1 1.8%
Egypt 1 1.8%
Italia 1 1.8%
Japón 1 1.8%
Malaysia 1 1.8%
Nizam's Institute Of Medical Sciences (Nims), Hyderabad, Telangana, India 1 1.8%
Polonia 1 1.8%
Russia 1 1.8%
Sweden 1 1.8%
Uruguay 1 1.8%
Show R code
df |>
  filter(!is.na(country_clean)) |>
  count(country_clean) |>
  slice_max(n, n = 12) |>
  mutate(country_clean = fct_reorder(country_clean, n)) |>
  ggplot(aes(x = n, y = country_clean, fill = n)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(aes(label = n), hjust = -0.3, size = 3.5, colour = "grey30") +
  scale_fill_gradient(low = pal_seq[2], high = pal_main[1]) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.2))) +
  labs(x = "Number of studies", y = NULL,
       title = "Geographic distribution of included studies",
       subtitle = "Top 12 countries shown") +
  theme_review()
Figure 3: Countries of origin of included studies (top 12).

1.4 Language of Publication

Show R code
df |>
  filter(!is.na(language_label)) |>
  count(language_label, name = "n") |>
  arrange(desc(n)) |>
  mutate(`%` = percent(n / sum(n), accuracy = 0.1)) |>
  rename(Language = language_label) |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = c(1, 3))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 3: Language of publication across included studies.
Language n %
English 49 89.1%
Spanish 3 5.5%
Other 2 3.6%
German 1 1.8%

1.5 Funding and Protocol Registration

Show R code
p1 <- df |>
  filter(!is.na(funding)) |>
  count(funding) |>
  mutate(label = if_else(funding == 1, "Funded", "Not funded")) |>
  ggplot(aes(x = "", y = n, fill = label)) +
  geom_col(width = 1) +
  coord_polar("y") +
  geom_text(aes(label = glue("{label}\n{n} ({percent(n / sum(n), accuracy = 1)})")),
            position = position_stack(vjust = 0.5),
            size = 3.2, colour = "white", fontface = "bold") +
  scale_fill_manual(
    values = c("Funded" = pal_main[1], "Not funded" = pal_main[3])) +
  labs(title = "Funding", fill = NULL) +
  theme_void() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        legend.position = "none")

p2 <- df |>
  filter(!is.na(protocol)) |>
  count(protocol) |>
  mutate(label = if_else(protocol == 1, "Registered", "Not registered")) |>
  ggplot(aes(x = "", y = n, fill = label)) +
  geom_col(width = 1) +
  coord_polar("y") +
  geom_text(aes(label = glue("{label}\n{n} ({percent(n / sum(n), accuracy = 1)})")),
            position = position_stack(vjust = 0.5),
            size = 3.2, colour = "white", fontface = "bold") +
  scale_fill_manual(
    values = c("Registered" = pal_main[2], "Not registered" = pal_main[4])) +
  labs(title = "Protocol registration", fill = NULL) +
  theme_void() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        legend.position = "none")

p1 + p2
Figure 4: Funding status and protocol registration across included studies.

Of the 55 included studies, 22 (40.0%) declared funding from an institutional, governmental, or industry source. Only 21 (38.2%) had a registered and publicly accessible protocol, representing a potential reporting bias risk that should be considered when interpreting findings.

1.6 Sample Size

Show R code
df |>
  filter(!is.na(total_n), total_n > 0) |>
  summarise(
    `Total participants (cumulative)` = sum(total_n),
    `Median sample size`              = median(total_n),
    `Q1 (25th percentile)`           = quantile(total_n, 0.25),
    `Q3 (75th percentile)`           = quantile(total_n, 0.75),
    `Minimum`                         = min(total_n),
    `Maximum`                         = max(total_n),
    `Studies with data`               = n()
  ) |>
  pivot_longer(everything(), names_to = "Statistic", values_to = "Value") |>
  mutate(Value = as.character(round(Value))) |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, 7, 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 4: Descriptive statistics of individual study sample sizes.
Statistic Value
Total participants (cumulative) 5544
Median sample size 65
Q1 (25th percentile) 49
Q3 (75th percentile) 102
Minimum 14
Maximum 1000
Studies with data 55
Show R code
med_n <- median(df$total_n, na.rm = TRUE)

df |>
  filter(!is.na(total_n), total_n > 0) |>
  ggplot(aes(x = total_n)) +
  geom_histogram(bins = 20, fill = pal_main[1], alpha = 0.8, colour = "white") +
  geom_vline(xintercept = med_n, colour = pal_main[3],
             linewidth = 1, linetype = "dashed") +
  annotate("text", x = med_n + 8, y = 9,
           label = glue("Median = {med_n}"),
           colour = pal_main[3], fontface = "bold", size = 3.5, hjust = 0) +
  scale_x_continuous(labels = comma) +
  labs(x = "Sample size (participants)", y = "Number of studies",
       title = "Distribution of individual study sample sizes") +
  theme_review() +
  theme(panel.grid.major.y = element_line(colour = "grey90"))
Figure 5: Distribution of individual study sample sizes.

2 Characteristics of Enrolled Participants

2.1 Age Groups

Show R code
# grupo_etario: 1=Neonato(0-28d), 2=Lactante menor(1-12m), 3=Lactante mayor(1-2y),
#               4=Preescolar(2-5y), 5=Escolar(6-10y), 6=Preadolescente(11-12y),
#               7=Adolescente(13-18y)
age_df <- tibble(
  `Age Group` = c(
    "Neonate (0–28 days)",
    "Young infant (1–12 months)",
    "Older infant (1–2 years)",
    "Preschool child (2–5 years)",
    "School-aged child (6–10 years)",
    "Pre-adolescent (11–12 years)",
    "Adolescent (13–18 years)"
  ),
  n = c(
    sum(df$grupo_etario___1, na.rm = TRUE),
    sum(df$grupo_etario___2, na.rm = TRUE),
    sum(df$grupo_etario___3, na.rm = TRUE),
    sum(df$grupo_etario___4, na.rm = TRUE),
    sum(df$grupo_etario___5, na.rm = TRUE),
    sum(df$grupo_etario___6, na.rm = TRUE),
    sum(df$grupo_etario___7, na.rm = TRUE)
  )
) |>
  mutate(`%` = percent(n / n_total, accuracy = 0.1))

age_df |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(age_df), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100)) |>
  tab_footnote("Studies enrolling multiple age groups are counted in each respective category.")
Table 5: Paediatric age groups represented across included studies.
Age Group n %
Neonate (0–28 days) 12 21.8%
Young infant (1–12 months) 37 67.3%
Older infant (1–2 years) 34 61.8%
Preschool child (2–5 years) 35 63.6%
School-aged child (6–10 years) 31 56.4%
Pre-adolescent (11–12 years) 27 49.1%
Adolescent (13–18 years) 18 32.7%
Studies enrolling multiple age groups are counted in each respective category.

The most frequently represented category was young infants (1–12 months), included in 37 studies (67.3%). Neonates (0–28 days) constituted the least frequently included group (12 studies; 21.8%), representing a critical evidence gap given their heightened physiological vulnerability.

Show R code
age_df |>
  mutate(`Age Group` = fct_reorder(`Age Group`, n)) |>
  ggplot(aes(x = n, y = `Age Group`, fill = `Age Group`)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({`%`})")),
            hjust = -0.1, size = 3.3, colour = "grey30") +
  scale_fill_manual(
    values = colorRampPalette(c(pal_seq[2], pal_main[1]))(7)) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.22))) +
  labs(x = "Number of studies", y = NULL,
       title = "Paediatric age groups represented in included studies",
       caption = glue("N = {n_total} studies; a study may include multiple age groups")) +
  theme_review()
Figure 6: Frequency of paediatric age groups across included studies.

2.2 ASA Physical Status Classification

Show R code
# clasificaci_n_asa: 1=ASA I, 2=ASA II, 3=ASA III, 4=ASA IV,
#                   5=ASA V, 6=ASA VI, 7=No information
asa_df <- tibble(
  `ASA Class` = c("ASA I", "ASA II", "ASA III", "ASA IV",
                  "ASA V", "ASA VI", "Not reported"),
  n = c(
    sum(df$clasificaci_n_asa___1, na.rm = TRUE),
    sum(df$clasificaci_n_asa___2, na.rm = TRUE),
    sum(df$clasificaci_n_asa___3, na.rm = TRUE),
    sum(df$clasificaci_n_asa___4, na.rm = TRUE),
    sum(df$clasificaci_n_asa___5, na.rm = TRUE),
    sum(df$clasificaci_n_asa___6, na.rm = TRUE),
    sum(df$clasificaci_n_asa___7, na.rm = TRUE)
  )
) |>
  mutate(`%` = percent(n / n_total, accuracy = 0.1))

asa_df |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(asa_df), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 6: ASA physical status classification across included studies.
ASA Class n %
ASA I 28 50.9%
ASA II 25 45.5%
ASA III 10 18.2%
ASA IV 1 1.8%
ASA V 0 0.0%
ASA VI 0 0.0%
Not reported 23 41.8%

3 Surgical Context and Procedural Types

3.1 Surgical Urgency Classification

Show R code
ctx_tab <- df |>
  filter(!is.na(context_label)) |>
  count(context_label, name = "n") |>
  arrange(desc(n)) |>
  mutate(`%` = percent(n / n_total, accuracy = 0.1)) |>
  rename(`Surgical Context` = context_label)

ctx_tab |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(ctx_tab), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 7: Surgical urgency classification across included studies.
Surgical Context n %
Planned (> 1 month) 37 67.3%
Unknown / unclear 7 12.7%
Elective priority (weeks) 4 7.3%
Urgent (< 24 hours) 4 7.3%
Semi-urgent (days) 3 5.5%
Show R code
df |>
  filter(!is.na(context_label)) |>
  count(context_label) |>
  mutate(context_label = fct_reorder(context_label, n)) |>
  ggplot(aes(x = n, y = context_label, fill = n)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({percent(n / n_total, accuracy = 1)})")),
            hjust = -0.1, size = 3.3, colour = "grey30") +
  scale_fill_gradient(low = pal_seq[2], high = pal_main[1]) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.25))) +
  labs(x = "Number of studies", y = NULL,
       title = "Surgical urgency classification") +
  theme_review()
Figure 7: Surgical urgency context across included studies.

The large majority of studies (37 studies; 67.3%) were conducted in planned or elective surgical settings, substantially limiting the generalisability of findings to urgent and emergency contexts.

3.2 Types of Surgical Procedure

Show R code
# type_surgery: 1=ENT, 2=Lap.Abd, 3=Open.Abd, 4=Neuro, 5=Transplant,
#               6=Ortho, 7=Thorax, 8=Maxilo, 9=Mixed, 10=Other
surg_df <- tibble(
  `Surgery Type` = c(
    "Open abdominal surgery",
    "Neurosurgery (craniotomy / spinal)",
    "Maxillofacial surgery",
    "Multiple/unspecified types",
    "Laparoscopic abdominal surgery",
    "Thoracic surgery",
    "Otorhinolaryngology",
    "Orthopaedic surgery",
    "Organ transplantation",
    "Other"
  ),
  n = c(
    sum(df$type_surgery___3,  na.rm = TRUE),
    sum(df$type_surgery___4,  na.rm = TRUE),
    sum(df$type_surgery___8,  na.rm = TRUE),
    sum(df$type_surgery___9,  na.rm = TRUE),
    sum(df$type_surgery___2,  na.rm = TRUE),
    sum(df$type_surgery___7,  na.rm = TRUE),
    sum(df$type_surgery___1,  na.rm = TRUE),
    sum(df$type_surgery___6,  na.rm = TRUE),
    sum(df$type_surgery___5,  na.rm = TRUE),
    sum(df$type_surgery___10, na.rm = TRUE)
  )
) |>
  arrange(desc(n)) |>
  mutate(`%` = percent(n / n_total, accuracy = 0.1))

surg_df |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(surg_df), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100)) |>
  tab_footnote("A single study may include more than one procedure type.")
Table 8: Types of surgical procedure included across studies.
Surgery Type n %
Other 21 38.2%
Open abdominal surgery 16 29.1%
Neurosurgery (craniotomy / spinal) 12 21.8%
Maxillofacial surgery 9 16.4%
Multiple/unspecified types 9 16.4%
Laparoscopic abdominal surgery 7 12.7%
Thoracic surgery 7 12.7%
Otorhinolaryngology 6 10.9%
Orthopaedic surgery 6 10.9%
Organ transplantation 3 5.5%
A single study may include more than one procedure type.
Show R code
surg_df |>
  mutate(`Surgery Type` = fct_reorder(`Surgery Type`, n)) |>
  ggplot(aes(x = n, y = `Surgery Type`, fill = n)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({`%`})")),
            hjust = -0.1, size = 3.2, colour = "grey30") +
  scale_fill_gradient(low = pal_seq[2], high = pal_main[1]) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.25))) +
  labs(x = "Number of studies", y = NULL,
       title = "Types of surgical procedures represented",
       caption = "A single study may report more than one procedure type") +
  theme_review()
Figure 8: Types of surgical procedures across included studies.

4 Types of Intravenous Fluids Used

A notable strength of this scoping review is the diversity of intravenous fluid types evaluated, encompassing unbalanced crystalloids, balanced crystalloids, dextrose-containing combined solutions, and both natural and synthetic colloids.

4.1 Fluid Types by Study Group

Show R code
# type_of_fluids / type_of_fluids_control:
# 1=NS0.9%, 2=Semi-isotonic0.45%, 3=1/4isotonic, 4=Balanced Hartmann,
# 5=Balanced Ringer Lactate, 6=Balanced Plasma-Lyte,
# 7=Combined crystalloid+dextrose, 8=Natural colloid, 9=Synthetic colloid,
# 10=Other
fluid_df <- tibble(
  `Fluid Type` = c(
    "Normal saline 0.9%",
    "Semi-isotonic 0.45%",
    "Quarter-isotonic",
    "Balanced: Hartmann's solution",
    "Balanced: Lactated Ringer's",
    "Balanced: Plasma-Lyte",
    "Combined crystalloid-dextrose",
    "Natural colloid (albumin)",
    "Synthetic colloid",
    "Other"
  ),
  `Intervention (n)` = c(
    sum(df$type_of_fluids___1,  na.rm = TRUE),
    sum(df$type_of_fluids___2,  na.rm = TRUE),
    sum(df$type_of_fluids___3,  na.rm = TRUE),
    sum(df$type_of_fluids___4,  na.rm = TRUE),
    sum(df$type_of_fluids___5,  na.rm = TRUE),
    sum(df$type_of_fluids___6,  na.rm = TRUE),
    sum(df$type_of_fluids___7,  na.rm = TRUE),
    sum(df$type_of_fluids___8,  na.rm = TRUE),
    sum(df$type_of_fluids___9,  na.rm = TRUE),
    sum(df$type_of_fluids___10, na.rm = TRUE)
  ),
  `Control (n)` = c(
    sum(df$type_of_fluids_control___1,  na.rm = TRUE),
    sum(df$type_of_fluids_control___2,  na.rm = TRUE),
    sum(df$type_of_fluids_control___3,  na.rm = TRUE),
    sum(df$type_of_fluids_control___4,  na.rm = TRUE),
    sum(df$type_of_fluids_control___5,  na.rm = TRUE),
    sum(df$type_of_fluids_control___6,  na.rm = TRUE),
    sum(df$type_of_fluids_control___7,  na.rm = TRUE),
    sum(df$type_of_fluids_control___8,  na.rm = TRUE),
    sum(df$type_of_fluids_control___9,  na.rm = TRUE),
    sum(df$type_of_fluids_control___10, na.rm = TRUE)
  )
) |>
  mutate(
    `Int. %`  = percent(`Intervention (n)` / n_total, accuracy = 0.1),
    `Ctrl. %` = percent(`Control (n)` / n_total, accuracy = 0.1)
  )

fluid_df |>
  gt() |>
  tab_header(title = "Fluid types across intervention and control groups") |>
  tab_spanner(label = "Intervention Group",
              columns = c(`Intervention (n)`, `Int. %`)) |>
  tab_spanner(label = "Control Group",
              columns = c(`Control (n)`, `Ctrl. %`)) |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#1F6B8F"),
            locations = cells_column_spanners()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_spanners()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(fluid_df), 2))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100)) |>
  tab_footnote("A single study may include more than one fluid type.")
Table 9: Intravenous fluid types by study group (intervention vs. control).
Fluid types across intervention and control groups
Fluid Type
Intervention Group
Control Group
Intervention (n) Int. % Control (n) Ctrl. %
Normal saline 0.9% 7 12.7% 10 18.2%
Semi-isotonic 0.45% 3 5.5% 6 10.9%
Quarter-isotonic 0 0.0% 0 0.0%
Balanced: Hartmann's solution 3 5.5% 3 5.5%
Balanced: Lactated Ringer's 12 21.8% 17 30.9%
Balanced: Plasma-Lyte 3 5.5% 2 3.6%
Combined crystalloid-dextrose 6 10.9% 14 25.5%
Natural colloid (albumin) 2 3.6% 3 5.5%
Synthetic colloid 6 10.9% 5 9.1%
Other 21 38.2% 13 23.6%
A single study may include more than one fluid type.
Show R code
fluid_df |>
  select(`Fluid Type`, `Intervention (n)`, `Control (n)`) |>
  pivot_longer(-`Fluid Type`, names_to = "Group", values_to = "n") |>
  mutate(
    Group = recode(Group,
      "Intervention (n)" = "Intervention",
      "Control (n)"      = "Control"
    ),
    `Fluid Type` = fct_reorder(`Fluid Type`, n, .fun = sum)
  ) |>
  ggplot(aes(x = n, y = `Fluid Type`, fill = Group)) +
  geom_col(position = position_dodge(width = 0.7), width = 0.6) +
  geom_text(aes(label = n),
            position = position_dodge(width = 0.7),
            hjust = -0.3, size = 3, colour = "grey30") +
  scale_fill_manual(
    values = c("Intervention" = pal_main[1], "Control" = pal_main[3])) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.2))) +
  labs(x = "Number of studies", y = NULL, fill = "Group",
       title = "Intravenous fluid types: intervention vs. control groups",
       caption = "A single study may include more than one fluid type") +
  theme_review()
Figure 9: Comparative frequency of fluid types in intervention and control groups.

Lactated Ringer’s solution was the most frequently evaluated balanced crystalloid — used as the intervention fluid in 12 studies and as the control in 17. Normal saline 0.9% served most often as a control comparator (10 studies). Combined crystalloid-dextrose solutions were especially prevalent in control groups (14 studies), underscoring their role as the conventional maintenance standard in infants and neonates.


5 Perioperative Phase and Administration Modality

5.1 Timing of Fluid Administration

Show R code
# time_adm: 1=Preoperative, 2=Intraoperative, 3=Postoperative, 4=Not specified
timing_df <- tibble(
  Phase = c("Preoperative", "Intraoperative", "Postoperative", "Not specified"),
  n = c(
    sum(df$time_adm___1, na.rm = TRUE),
    sum(df$time_adm___2, na.rm = TRUE),
    sum(df$time_adm___3, na.rm = TRUE),
    sum(df$time_adm___4, na.rm = TRUE)
  )
) |>
  mutate(`%` = percent(n / n_total, accuracy = 0.1))

timing_df |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = c(1, 3))) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100))
Table 10: Perioperative phase of fluid administration.
Phase n %
Preoperative 15 27.3%
Intraoperative 51 92.7%
Postoperative 22 40.0%
Not specified 1 1.8%
Show R code
timing_df |>
  mutate(Phase = fct_reorder(Phase, n)) |>
  ggplot(aes(x = n, y = Phase, fill = Phase)) +
  geom_col(width = 0.6, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({`%`})")),
            hjust = -0.1, size = 3.5, colour = "grey30") +
  scale_fill_manual(
    values = c(pal_main[1], pal_main[2], pal_main[3], "grey70")) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.22))) +
  labs(x = "Number of studies", y = NULL,
       title = "Perioperative phase of fluid administration",
       caption = "A single study may report administration across multiple phases") +
  theme_review()
Figure 10: Perioperative phase of fluid administration across included studies.

The intraoperative phase was the most extensively studied period (51 of 55 studies; 92.7%). Postoperative and preoperative phases were evaluated in 22 and 15 studies respectively, representing important evidence gaps.

5.2 Preoperative Fasting

Show R code
df |>
  filter(!is.na(ayuno)) |>
  count(ayuno) |>
  mutate(label = if_else(ayuno == 1,
                         "Reported fasting protocol", "Not reported")) |>
  ggplot(aes(x = n, y = label, fill = label)) +
  geom_col(width = 0.5, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({percent(n / sum(n), accuracy = 1)})")),
            hjust = -0.1, size = 3.5, colour = "grey30") +
  scale_fill_manual(
    values = c("Reported fasting protocol" = pal_main[1],
               "Not reported" = "grey70")) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.3))) +
  labs(x = "Number of studies", y = NULL,
       title = "Preoperative fasting protocol reporting") +
  theme_review()
Figure 11: Proportion of studies reporting a preoperative fasting protocol.

5.3 Follow-Up Duration

Show R code
df |>
  filter(!is.na(followup_label)) |>
  count(followup_label, .drop = FALSE) |>
  ggplot(aes(x = n, y = followup_label, fill = followup_label)) +
  geom_col(width = 0.6, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({percent(n / n_total, accuracy = 1)})")),
            hjust = -0.1, size = 3.4, colour = "grey30") +
  scale_fill_manual(
    values = colorRampPalette(c(pal_seq[2], pal_main[1]))(5)) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.25))) +
  labs(x = "Number of studies", y = NULL,
       title = "Duration of follow-up") +
  theme_review()
Figure 12: Duration of follow-up across included studies.

6 Reported Outcomes and Principal Findings

6.1 Overview of Evaluated Outcomes

Show R code
# outcomes: 1=Electrolyte, 2=Acid-base, 3=Hyperchloraemic acidosis,
#           4=AKI, 5=Oedema formation, 6=Hypoglycaemia, 7=Hyperglycaemia,
#           8=Postop ileus, 9=Coagulopathy, 10=Haemodynamics, 11=Oedema,
#           12=Hospital stay, 13=ICU stay, 14=Other
outcomes_df <- tibble(
  Outcome = c(
    "Electrolyte disturbances",
    "Acid-base status alterations",
    "Haemodynamic stability",
    "Hypoglycaemia",
    "Hyperglycaemia",
    "Acute kidney injury",
    "Dilutional coagulopathy / platelet dysfunction",
    "Length of ICU stay",
    "Length of hospital stay",
    "Hyperchloraemic acidosis",
    "Oedema (formation / general)",
    "Postoperative ileus",
    "Other outcomes (uncategorised)"
  ),
  n = c(
    sum(df$outcomes___1,  na.rm = TRUE),
    sum(df$outcomes___2,  na.rm = TRUE),
    sum(df$outcomes___10, na.rm = TRUE),
    sum(df$outcomes___6,  na.rm = TRUE),
    sum(df$outcomes___7,  na.rm = TRUE),
    sum(df$outcomes___4,  na.rm = TRUE),
    sum(df$outcomes___9,  na.rm = TRUE),
    sum(df$outcomes___13, na.rm = TRUE),
    sum(df$outcomes___12, na.rm = TRUE),
    sum(df$outcomes___3,  na.rm = TRUE),
    sum(df$outcomes___5,  na.rm = TRUE) + sum(df$outcomes___11, na.rm = TRUE),
    sum(df$outcomes___8,  na.rm = TRUE),
    sum(df$outcomes___14, na.rm = TRUE)
  )
) |>
  arrange(desc(n)) |>
  mutate(`%` = percent(n / n_total, accuracy = 0.1))

outcomes_df |>
  gt() |>
  tab_style(style = cell_fill(color = "#2E4A8F"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_text(color = "white", weight = "bold"),
            locations = cells_column_labels()) |>
  tab_style(style = cell_fill(color = "#F2F6FB"),
            locations = cells_body(rows = seq(1, nrow(outcomes_df), 2))) |>
  tab_style(style = cell_text(weight = "bold"),
            locations = cells_body(rows = 1:3)) |>
  opt_table_lines("none") |>
  tab_options(table.width = pct(100)) |>
  tab_footnote("A single study may report more than one outcome.")
Table 11: Clinical outcomes reported across included studies.
Outcome n %
Other outcomes (uncategorised) 38 69.1%
Electrolyte disturbances 35 63.6%
Acid-base status alterations 33 60.0%
Haemodynamic stability 26 47.3%
Hypoglycaemia 22 40.0%
Hyperglycaemia 21 38.2%
Acute kidney injury 14 25.5%
Dilutional coagulopathy / platelet dysfunction 8 14.5%
Length of ICU stay 7 12.7%
Length of hospital stay 5 9.1%
Hyperchloraemic acidosis 5 9.1%
Oedema (formation / general) 5 9.1%
Postoperative ileus 0 0.0%
A single study may report more than one outcome.
Show R code
outcomes_df |>
  filter(Outcome != "Other outcomes (uncategorised)") |>
  mutate(
    Outcome    = fct_reorder(Outcome, n),
    highlight  = n >= 20
  ) |>
  ggplot(aes(x = n, y = Outcome, fill = highlight)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} ({`%`})")),
            hjust = -0.1, size = 3.2, colour = "grey30") +
  scale_fill_manual(
    values = c("TRUE" = pal_main[1], "FALSE" = pal_main[2])) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.28))) +
  labs(x = "Number of studies", y = NULL,
       title = "Reported clinical outcomes across included studies",
       subtitle = "Darker colour = outcome reported in \u2265 20 studies",
       caption = "'Other outcomes' category excluded from this figure") +
  theme_review()
Figure 13: Frequency of reported clinical outcomes across included studies.

6.2 Outcome Co-occurrence

Show R code
out_mat <- df |>
  transmute(
    `Electrolytes`   = outcomes___1,
    `Acid-base`      = outcomes___2,
    `Haemodynamics`  = outcomes___10,
    `Hypoglycaemia`  = outcomes___6,
    `Hyperglycaemia` = outcomes___7,
    `AKI`            = outcomes___4
  ) |>
  mutate(across(everything(), ~ replace_na(as.integer(.x), 0L)))

co_df <- crossprod(as.matrix(out_mat)) |>
  as.data.frame() |>
  rownames_to_column("Outcome1") |>
  pivot_longer(-Outcome1, names_to = "Outcome2", values_to = "Count")

ggplot(co_df, aes(x = Outcome1, y = Outcome2, fill = Count)) +
  geom_tile(colour = "white", linewidth = 0.5) +
  geom_text(aes(label = Count), size = 3.5,
            fontface = "bold", colour = "white") +
  scale_fill_gradient(low = pal_seq[2], high = pal_main[1]) +
  labs(x = NULL, y = NULL, fill = "Studies",
       title = "Outcome co-occurrence matrix",
       subtitle = "Diagonal = studies reporting that single outcome; off-diagonal = studies reporting both",
       caption = "Six most frequently reported outcomes shown") +
  theme_review() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1),
        panel.grid  = element_blank())
Figure 14: Co-occurrence matrix of the six most frequently reported outcomes.

7 Narrative Synthesis

7.1 Electrolyte Disturbances and Acid-Base Homeostasis

Electrolyte disturbances were the most frequently evaluated outcome domain (35 studies; 63.6%), with particular emphasis on serum sodium, chloride, and potassium concentrations. Hyponatraemia emerged as a consistent concern across studies comparing hypotonic and isotonic maintenance fluids in the postoperative setting: hypotonic solutions were systematically associated with a higher risk of symptomatic and asymptomatic hyponatraemia, whilst isotonic or mildly hyperosmolar solutions carried a greater risk of hypernatraemia and hyperchloraemia.

Acid-base homeostasis was evaluated in 33 studies (60.0%) and demonstrated systematic differences between balanced and unbalanced crystalloids. Administration of normal saline 0.9% was consistently associated with a higher incidence of hyperchloraemic metabolic acidosis — characterised by declining serum bicarbonate, negative base excess, and elevated plasma chloride — an effect considerably attenuated with Lactated Ringer’s and largely absent with Plasma-Lyte.

7.2 Glycaemic Status

Perioperative glycaemic management was a central clinical concern in studies enrolling neonates and young infants. Hypoglycaemia was evaluated in 22 studies and hyperglycaemia in 21. Evidence from included studies suggests that the addition of dextrose at concentrations of 1–2% to maintenance fluids can effectively prevent intraoperative hypoglycaemia without significantly increasing hyperglycaemia. Higher dextrose concentrations (≥5%) were associated with hyperglycaemic episodes carrying potential adverse consequences for wound healing and cerebral function.

7.3 Haemodynamic Stability and Renal Function

Haemodynamic stability was evaluated in 26 studies (47.3%). The different fluid types evaluated generally did not demonstrate clinically meaningful differences in intraoperative haemodynamic stability when administered in appropriate volumes. In settings characterised by significant blood loss, colloids demonstrated superior short-term efficacy for rapid volume expansion, though with recognised long-term adverse effects.

Acute kidney injury was evaluated in 14 studies (25.5%). Balanced crystalloids demonstrated a more favourable renal safety profile compared with NS 0.9%, primarily through attenuation of hyperchloraemia-mediated renal vasoconstriction. Studies comparing synthetic colloids — particularly hydroxyethyl starches — with crystalloids reported, in some instances, a higher incidence of AKI with starch-based solutions.

7.4 Length of Stay Outcomes

Show R code
tibble(
  Outcome = c("Length of hospital stay", "Length of ICU stay"),
  n       = c(
    sum(df$outcomes___12, na.rm = TRUE),
    sum(df$outcomes___13, na.rm = TRUE)
  )
) |>
  mutate(pct = percent(n / n_total, accuracy = 1)) |>
  ggplot(aes(x = n, y = Outcome, fill = Outcome)) +
  geom_col(width = 0.45, show.legend = FALSE) +
  geom_text(aes(label = glue("{n} studies ({pct})")),
            hjust = -0.1, size = 3.5, colour = "grey30") +
  scale_fill_manual(values = c(pal_main[2], pal_main[1])) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.5)),
                     limits = c(0, 20)) +
  labs(x = "Number of studies", y = NULL,
       title = "Length-of-stay outcomes in included studies") +
  theme_review()
Figure 15: Proportion of studies reporting length-of-stay outcomes.

Length of hospital stay was evaluated in only 5 studies (9.1%) and ICU stay in 7 studies (12.7%). This limited representation constitutes a significant evidence gap, given the important implications of fluid optimisation for postoperative recovery trajectories and healthcare resource utilisation.


8 Evidence Gaps and Implications for Future Research

Show R code
n_ctx_valid <- sum(!is.na(df$context_label))

gap_data <- tibble(
  Item = c(
    "Neonates represented",
    "Emergency/urgent surgical context",
    "Protocol registered",
    "Follow-up > 7 days",
    "Postoperative phase evaluated",
    "Length of stay reported",
    "Fasting protocol reported",
    "High-income country studies"
  ),
  Represented = c(
    sum(df$grupo_etario___1, na.rm = TRUE),
    sum(df$context_label %in%
          c("Urgent (< 24 hours)", "Emergency (< 1 hour)"), na.rm = TRUE),
    sum(df$protocol == 1, na.rm = TRUE),
    sum(df$followup_label %in%
          c("7–14 days", "15–30 days", "> 30 days"), na.rm = TRUE),
    sum(df$time_adm___3, na.rm = TRUE),
    sum(df$outcomes___12, na.rm = TRUE) + sum(df$outcomes___13, na.rm = TRUE),
    sum(df$ayuno == 1, na.rm = TRUE),
    sum(df$country_clean %in%
          c("Germany","Sweden","Australia","United Kingdom","France",
            "USA","Spain","Italy","Japan","Canada","Austria",
            "Poland","Russia","South Korea"), na.rm = TRUE)
  ),
  Total = n_total
) |>
  mutate(
    pct_rep  = Represented / Total,
    Category = if_else(pct_rep < 0.35, "Gap", "Adequate")
  )

gap_data |>
  mutate(Item = fct_reorder(Item, pct_rep)) |>
  ggplot(aes(x = pct_rep, y = Item, fill = Category)) +
  geom_col(width = 0.65) +
  geom_vline(xintercept = 0.5, linetype = "dashed",
             colour = "grey50", linewidth = 0.7) +
  geom_text(
    aes(label = glue("{Represented}/{Total} ({percent(pct_rep, accuracy = 1)})")),
    hjust = -0.08, size = 3.2, colour = "grey25") +
  scale_fill_manual(
    values = c("Gap" = "#D94F3D", "Adequate" = pal_main[1]),
    name = "Evidence status") +
  scale_x_continuous(labels = percent, limits = c(0, 1.1),
                     expand = expansion(mult = c(0, 0))) +
  labs(x = "Proportion of studies", y = NULL,
       title = "Key evidence characteristics and identified gaps",
       subtitle = "Red = gap (< 35% of studies); blue = adequate; dashed line = 50%",
       caption = glue("Based on {n_total} included studies")) +
  theme_review()
Figure 16: Summary dashboard of key evidence characteristics and identified gaps.

The analysis of the 55 included studies reveals several significant evidence gaps:

Neonatal population. Neonates were included in only 12 studies (21.8%), despite representing the most physiologically vulnerable group. Their renal immaturity, heightened susceptibility to hypoglycaemia, and immature sodium homeostatic mechanisms necessitate age-specific protocols that the current literature cannot adequately support.

Emergency and urgent contexts. Only 4 studies were conducted in patients requiring urgent or emergency surgical intervention — a near-total evidence absence with clinically consequential implications.

Outcome heterogeneity. The absence of validated, standardised Core Outcome Sets (COS) for evaluating perioperative fluid therapy in paediatric populations impedes cross-study comparison and the synthesis of evidence into actionable clinical recommendations.

Limited long-term follow-up. Only 4 studies maintained follow-up beyond seven days. Effects on health-related quality of life, functional recovery, and delayed complication rates remain largely uncharacterised.

Geographic imbalance. The large majority of evidence originates from high-complexity tertiary centres in high-income countries, limiting generalisability to resource-constrained settings where fluid availability and clinical contexts differ markedly.


9 Conclusions

The evidence synthesised across 55 included studies reflects a progressively expanding field of inquiry. The predominance of randomised controlled trials (44/55; 80.0%) provides a methodologically sound foundation for comparative analyses, albeit consistently limited sample sizes constrain statistical power.

Balanced crystalloids — most notably Lactated Ringer’s solution — emerge as physiologically superior to normal saline 0.9% with respect to acid-base preservation and hyperchloraemia prevention. Dextrose-containing combined solutions remain clinically indispensable for neonates and young infants, though optimal concentration and infusion rate require further investigation. Colloids occupy a defined niche for acute volume expansion in haemodynamically compromised patients, but lack robust evidence for routine use in elective paediatric surgery.

The intraoperative phase is the best-characterised period; preoperative and postoperative fluid management represent domains with substantially more limited evidence. Future studies with adequate sample sizes, prolonged follow-up, standardised outcomes, inclusive enrolment criteria, and representation of emergency contexts are urgently needed to generate evidence-based guidelines applicable across the full spectrum of paediatric non-cardiac surgery.


10 Session Information

sessionInfo()
R version 4.5.2 (2025-10-31)
Platform: aarch64-apple-darwin20
Running under: macOS Tahoe 26.2

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/Bogota
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] glue_1.8.0       kableExtra_1.4.0 patchwork_1.3.2  ggtext_0.1.2    
 [5] janitor_2.2.1    scales_1.4.0     gtExtras_0.6.2   gt_1.3.0        
 [9] lubridate_1.9.5  forcats_1.0.1    stringr_1.6.0    dplyr_1.2.0     
[13] purrr_1.2.1      readr_2.2.0      tidyr_1.3.2      tibble_3.3.1    
[17] ggplot2_4.0.2    tidyverse_2.0.0 

loaded via a namespace (and not attached):
 [1] gtable_0.3.6       xfun_0.56          htmlwidgets_1.6.4  lattice_0.22-7    
 [5] paletteer_1.7.0    tzdb_0.5.0         vctrs_0.7.1        tools_4.5.2       
 [9] generics_0.1.4     parallel_4.5.2     pkgconfig_2.0.3    Matrix_1.7-4      
[13] RColorBrewer_1.1-3 S7_0.2.1           lifecycle_1.0.5    compiler_4.5.2    
[17] farver_2.1.2       textshaping_1.0.4  fontawesome_0.5.3  snakecase_0.11.1  
[21] sass_0.4.10        htmltools_0.5.9    yaml_2.3.12        pillar_1.11.1     
[25] crayon_1.5.3       nlme_3.1-168       tidyselect_1.2.1   digest_0.6.39     
[29] stringi_1.8.7      rematch2_2.1.2     splines_4.5.2      labeling_0.4.3    
[33] fastmap_1.2.0      grid_4.5.2         cli_3.6.5          magrittr_2.0.4    
[37] withr_3.0.2        bit64_4.6.0-1      timechange_0.4.0   rmarkdown_2.30    
[41] bit_4.6.0          hms_1.1.4          evaluate_1.0.5     knitr_1.51        
[45] viridisLite_0.4.3  mgcv_1.9-3         rlang_1.1.7        gridtext_0.1.6    
[49] Rcpp_1.1.1         xml2_1.5.2         svglite_2.2.2      rstudioapi_0.18.0 
[53] vroom_1.7.0        jsonlite_2.0.0     R6_2.6.1           systemfonts_1.3.1 
[57] fs_1.6.6