Yes. With Typst bundled into Rust and deployed on AWS Lambda, cached template rendering can run below 2 milliseconds, although the result depends on template complexity and caching.
🔒 14 more in the full analysis
Searchable transcript of How We Replaced Crystal Reports with Rust & Typst (Sub-2ms PDFs) — InfoQ (38:47). Search for a phrase, then click its timestamp to jump straight to that moment in the video.
Captions sourced from the original video on YouTube, published by InfoQ. The video, its captions and all related intellectual property remain the property of their respective owners; AINotes claims no ownership. Provided for research, accessibility and search — see the Transcript Notice and Copyright Policy.
00:04 Okay. Hello all. Um, I will be talking today about PDFs. I know currently we have the era of AI and every other talk has mostly to do something with LLMs. And I have to say my background is also in AI and software. But because of the last one and a half years where I've been working in consulting and with companies that do a lot of lot with um documents especially um in the compliance area that has been like a pain point of mine and I wrote about it and it kind of struck a nerve and just to understand where you're
00:45 sitting or why you are here um I would like to see who of you came to this talk because you also had something to do with PDFs and have a painoint and it's maybe something you're trying to solve. Maybe some of you are here because um it mentioned rust and or typed no one yeah rust or types rust okay or someone with like serverless and so on. Okay. Um yeah, let's dive into it.
01:19 The two experiences I had last year were one case at the bank who was trying to scale. So as you can can imagine like most banks is like legacy software and it actually still is cobalt running the show for at least the client where I was and especially the PDF pipeline that they had was getting too slow. So it's like at a point where the customer you are buying something like a stock or something and you're waiting for days to for the PDF to arrive.
01:55 And it's not only inconvenient, it's regulatory not allowed. And at some point the the German regulatory institute was like guys you cannot do this. So they were kind of forced to change and then they started thinking okay what do we do and obviously there was this big movement of bringing everything into the cloud. So they thought about yeah can we use AWS L lambda and at this point I already moved on to another project because I was moved out and from colleagues who still work there I heard that it was like one or
02:33 two years they were still trying to figure out how can we do PDF rendering in a nice pipeline and I just heard something with Java and pre-ompiled like compiled programs based on every template and I was like this is going to be a mess and I don't know I'm not in contact anymore but I don't think they have updated since like 2 years and the second experience was in manufacturing there was more it was not the speed or the latency of every PDF is was more how do we manage because it was in a regulated industry where you
03:08 want to know when you like when a truck leaves the facility it needs the right waiting slip that says okay so many tons weighs the truck and what kind of gas for example is in there if it's for example medical gas there are regulatory requirements and I worked on the in the manufacturing I worked on it for some time and I can tell you the workflow was somewhere like this the customer has some problem yeah the truck driver can't leave because the certificate is just not getting printed so he calls us because we were
03:42 like the service provider for this system and we had first to jump through two VPNs to some remote desktop to see is it actually an error, is it a user error, where's the where's the PDF? Then because how the system was built up, we had to take a whole backup of the production database which was like five, six, seven data uh ga gigabytes downloaded through the two VPNs.
04:11 then put the whole backup file um into our test environment, create the valid fake order because how the system was was created, you had to have a order when you want to test if a certificate can be printed and then try to reproduce it. And I felt because I came from from working with startups um that everything was Yeah. And also like it was a lot of this like waiting waiting for a long time and I came um from from somewhere where we used modern tools and not these outed tools.
04:52 I don't who of you knows crystal report would you say would you speak highly of it? They're like they're like thumbs down in the last row. Um it was actually really a painoint. For those of you who don't know, it's a software from it originated in 1984, which is like very long time. I don't know if we had PCs back there, but seems like it. And you how it worked is you connected it through like credentials to a database.
05:22 Then it would fetch the schema and there you see like on the left side there are like this little fields where you can then drag drag and drop it into your PDF and that's how you build it. And now imagine because we had a lot of um factories in in different countries and then there cames like we have a new factory in in check can you please translate this means you click on every thing you see you click on everything copy paste it into deepel or I don't know your llm and replace it and this was like this was horrible
05:56 it kind of broke me mentally I feel like and other tools if you look around what how the ULs can generate PDFs there like other tools for example latte does some of you come from like a scientific background and knows latte yeah some yeah for those who don't it's kind of you can think of it like a programming language that spits out the PDF um I know it because from my studies in math and if you try to like do formulas in word it will definitely break you so latte is something where you just have code for how to do
06:35 like a pi sign and so on. And another thing that's used in the industry of is something like puppeteer and this goes more into like web development because you render your PDF through through web technologies like Chrome and you just take the PDF and download it. Obviously, it has its drawbacks because you have this whole overhead of creating an headless Chrome instance like a browser that renders it and then spits out the PDF.
07:04 [snorts] The benefits are obviously you can use talents or if you know CSS you can probably get around and build a PDF for you. For latte for example, you would have to learn how to set like a section, a break and so on. And I felt like coming from startups working where working with code that was managed with Git where you had something like reproducibility with Docker and CI/CD.
07:30 I felt like working with documents in in the in the projects that I worked with was like super horrible. Our and it was always like kind of like embrace the chaos and just like spend four or five hours until it works. And I always felt like there is room for improvement and kind of like my early Christmas wish list for this would be obviously speed.
07:59 So if you're like someone who needs to render a million PDFs by the end of the day, for example, like if you're a bank or a broker, but also memory consumption because like spinning up a whole browser just to print a PDF is probably not the most efficient way. Version control is like something that we as developers we know and kind of also love and are also dependent.
08:21 Like I remember back 15 years when you wouldn't know git and you start writing your files as final version v3 or for some projects and in general like the modern developer experience of something like syntax highlighting crossplatform. So like crystal report for example that I show earlier it only works on Windows and it also work only works on Windows like not even the ARM version where I was working I tried to use my Mac but because my Mac is like um the new Apple silicon which is ARM based Crystal Report was having
09:00 none of it when I use tried to use a virtual machine and one big thing was um you saw with the workflow we spent a long time to download a whole database just to get this connection and try to test it. And in the end, we actually just wanted the JSON with the data we want to print. And so for those who know Latte, the past few years they came a new type setter from a team in Berlin based on a master thesis and what they share uh latte and types.
09:36 They are both type setters. This means it's not like word where you you get a PDF like what you see. It's more like you have the code where you write this is my text and format it please very nicely. So you have nice uh paragraph breaks and so on. And you see um here on the right side that the syntax resembles like a some kind of DSL where you have for example some kind of markdom DSL where you have these equal signs for a for a section header and so on.
10:09 And the nice thing is it's it's more lean than Latte. For those who worked with latte and tried to install it on the PC, it's like it's it's 5 GB for the whole distribution. It's very complicated. There's a lot of dependencies. Types is like a modern rewrite way. It's just like you download it, which is I think less than 50 megabytes and then you just compile the file you want to compile into a PDF.
10:40 It's not only more modern in the developer experience, it's also faster for larger files and it has very nice error messaging. So for latte, for example, if you have something that breaks because the variable is not right, you would get huge error messages and you're like just lost. And here you get really good error messages. So my idea was then okay, so we have types can what can we do with it?
11:06 And in our case, what we want to do, we have a template, something on the right, and we have our data that comes from from a machine that comes from customer data from our database. How can we inject it? Because in the original idea of types, you would prepare a template, a fixed file, and you would print it into a PDF. But we want something in between.
11:30 We want the fixed template that always looks like this. If you have if you have invoices, you always want them to look in the same way, right? But you want to replace the name, the invoice ID and so on. And we want or I wanted something where it was very easy to use as a library in the language you wanted to use. And for example, you see down there in its easiest sense, it's just like render this template there.
11:57 It's just a string, but obviously you can get it from f from the file system and then just some JSON with the data. So that was kind of the goal and I wrote an blog post article where I used types and bundled it into something that was then deployed on AWS Lambda and it used technologies like Lambda Terraform to just have infrastructure as code and it was uh implemented in Rust [snorts] and it was kind of like a side project for me to kind of like show for me that there it there's like an opportunity for something
12:39 better to be had than crystal repo what everyone was using and I posted about it and it got some at least for me a lot of impressions and it's also the reason why I'm here because Renato one of the organizers saw it and asked me if I wanted to speak about it and also there was um I posted uh on Reddit about it and there were also some people that definitely felt the pain on gen generating PDFs and it surprised me actually a little bit and also they're like bad crystal report memories from internship and it seems like
13:12 there's obviously a community that shares this pain. The architecture that I uh went for for this serverless approach on AWS looked something like this. So you would have two lambdas, two functions. The first one was actually kind of dumb because it was just taking a request and putting it into a queue. This is the SQS you see there. And the second function was um kind of bundling types into a AWS function and was reading reading the request getting the template from from S3 and printing the PDF and putting it back
13:55 into S3 bucket. What made this possible or what it relies heavily on was cargo lambda. It's a way for writing rustbased uh AWS lambdas. And you can imagine the result looked something like this that you have your your endpoint. You give it the name of the template you want to print and the data. And what comes out of it was just a confirmation. A we cued it.
14:24 It's going to be rendered. Obviously at this point there's no no uh re retry and error handling. It was just about can we use types to get the performant rendering and we can. So the results were quite astonishing in the sense that it uses way less memory than original like traditional approaches like spinning up a whole browser or having this lot lat.
14:53 like um below 50 mgabytes and the rendering is below 100 milliseconds. So in the twodigit uh milliseconds and to if you scale this up it only costs uh less than 50 cents to render a million PDFs in comparison that's like 20 times less than with other approaches and okay but there you ask okay this is just this is just speed in a way and I was also not happy because what this didn't um work on was the whole management of PDFs And um a nice thing also for you if you have some site project I can only recommend put it on
15:35 somewhere Reddit or so because they will find the mistakes for you and you just then find for example I didn't know that if you if you have provisioned concurrency it generates billing the whole time. Um, and there was also some some points where I thought, yeah, you could actually just remove the free parts and like call the lambda that renders it directly through the lambda function URL.
16:02 And I did some tracing to find out what so what's the what's the actual speed? How much can we get out of it? And it turns out if you have some caching in place for on the template, you can imagine what types does. It gets a template with some variables and then it lays lays it out on like the PDF how how wide how big words are. But [snorts] if you just change a little part like below where it's like a new number, the rest can stay compiled.
16:30 You cache it and you just replace this part. And this makes it so fast that on a very small um AWS Lambda, you can get the rendering below 2 milliseconds because most of it is cached. Um, obviously there were some improvements. For example, the upload to PDA to to the S3 was still like one after another. So, this could be improved to reduce another 30%.
16:59 So, what we got to this point was a a rendering engine that works on simple templates. So, you can imagine the text templates for types, you can open them with your with your code editor and you can type it. you can put it into git and you see git differences. The input was JSON. So that's something you can very easily mock up. The developer experience was very good because you could compile it on your PC.
17:25 I could compile it for ARM for the Linux environment on on AWS and the performance was also really great. But what's what was lacking was that what do you do if you're like a bank or financial institution? you want to use the servers you already have in your basement. You're not going to use AWS or maybe you shouldn't. How do you really do version control on these templates?
17:52 Because creating a Git repository for for every template you have is definitely not like recommended from my side. Multifile support was also not was also not there. You can imagine you don't want a massive massive file where you have like 2,000 10,000 lines. You want to structure it. You want to include maybe maybe um images, logos and so on. So this was also not in the first version that I worked on and the debugging was also still not great.
18:25 So I thought to myself what what would we need or where can we draw um motivation or inspiration for and it was something like Docker Hub or package managers because they have strict versioning you know for Docker for example that you you not only know okay I have this docker image for Python you can even specify by a hash which specific version which layer do you get and bas Based on this I draw together some ideas which I wanted to work on and this is the first thing is content addressable storage.
19:05 You can think of it like that you you take a file you take an image and you don't store it by the name logo.png PNG, but you you hash the content, you get some you get some hash of random numbers, and then you just take this as your file name, which this gives you is you automatically get dduplication. If you now have a lot of templates that use the same logo, because it's the same file, they not going to be uh duplicated because it's the same file.
19:39 So, you get the same hash. So you don't get multiple files and something uh like text that we know from working with git where you have like branches. I wanted something that's first easy to use and like to be human readable. So to say okay I have this invoice at latest. So it's the latest version. Maybe you have something like invoice at version three for like the next roll out for when you have a new corporate design or so.
20:07 But sometimes if you have if you have in a regulated industry, you want to be sure that you take the template where the team came and said, "Oh, this is going we we're going to fix it and I want to be sure that we always take this template." So there's also a way to specify a specific template and not only template because you have to understand understand what means template not only file but the bundle and then we come to the next part we have we need a way where we can bundle logos assets like fonts into one package
20:47 such that the output is always the same. And the last part is obviously we want it still to be a nice library that we can use for example in a server approach when we later build like the next step. And just to show you how this could look like imagine you have an end point like a your back end where you manage all your PDF templates where you can say take this where you see main type.
21:13 This is like the main entry point. This is the main template and you can attach files to it and add some metadata. What you get back then is is a hash which is kind of representation of all the data you put in. If you look at it how it is stored, you would see that it creates a manifest file with this hash that you got back. So this gets stored and the content looks like this.
21:44 It's similar to um if you if you know how git works, it also builds something like an Merkel tree that we know from um from cryptocurrencies. It builds like a tree here where we where we reference the data we will later pull into our template by their hashes. We build like a JSON document out of it and then hash it again. So when I say I want a template starting with 39 A9, this means get me these files and put them into a bundle and then render it.
22:25 And if we work now with references because you don't always want to remember the whole hash, right? So we can also create references. This mean this only means that latest points to this hash and this hash is again this manifest file. So the whole flow looks kind of like if I type an invoice latest. We look at the reference, we take the hash, we take the manifest and then later pull from storage all the blob files can be the image can be the main main uh template.
22:57 So coming back to um the workflow this meant that when our customer would call us and say hey the certificate that we tried to print it didn't work. This means that we could just because we store not only the template but also the data. We could look up at renders we did that contains some kind of in this case ID of the order. We could look up and then we see there's this failed render entry where we get the we get the render ID, we get the template reference, we even get a hash to the data that was used.
23:38 And if you store also the data that was used to render, you could look up if it's maybe maybe they forgot something. In this case, maybe they probably forgot the expiry date. And this means we can reproduce failed renders like take the take the data that was used, download it, inspect it, test it, and test it. so long until you get it right. And to show like zoom out a bit.
24:11 So the the product the thing I did with the AWS serverless was mainly the rendering engine but you can go back and build the registry on top using modern techniques we know from something like Docker Hub or package managers where we have template management. it's more compliant and you get analytics because it's also if you have a large factory that that prints a lot of documents, you also want to know which one failed in the last week and then inspect why.
24:45 And then if you have something like this, it's pretty easy to to build a server on top that you can then horizontally and vertically scale. You have parallelization that's pretty nicely uses all your CPU cores without much of a headache on your side. You get strong caching which reduces the latency even further. And you just have a modern data interface where you can use something like JSON.
25:16 And to give you even like uh where this could lead or how how you can think of it is that you can even put something like a I said like we had this talk this keynote in the morning and this would be like the premcp like still a normal UI where you would see the past renders that your your faculty did which one failed why they failed. you can download the PDF, you can inspect the data.
25:49 So from this um it was kind of or how to say um coming back and thinking where the old tools were like latte being very very heavy very big uh dependencies. Um you would need like 5 GB to install it like the Docker images to install Latte is like huge. In this case, if you bundle it, it's less than 100 megabyte. Then crystal report is still was dependent on having an active database connection.
26:22 You also don't need that here. You just have your template and you give it some data. And also like puppeteer, I don't know who of you have tried to render something with that. And there the problem is always the nice thing is you you get these guarantees that you can design it with CSS but it's it's very it consumes a lot of memory because you you have long cold start times.
26:51 If you try to use something like Puppeteer on AWS um Lambda it's going to be quite slow because you need like at least a second to start the to start the the browser. So this was kind of um show at least the project for me where I saw that you could use modern tooling that is was originally meant for scientific work. So it was meant like types was was meant to print scientific papers but because how how performant it is you can use it also for document generation in the industry.
27:31 And if we now take then modern tooling that we see from from Docker, from git, from version control, we even get something where we have strong compliance guarantees. We can manage it very nicely and we then where we always get the PDF that we want in the beginning. Um for those of you who are interested or you think this could be relevant for you um all the code and all that I mentioned is uh open source.
28:04 Even the original typed PDF renderer is open source. So um if it's something for you look into it and um yeah reach out if you have something. Um, this was meant al also or I would try to have a bit of a Q&A. So feel free to raise some questions. But that's the first from my side. [applause] >> Yes. >> Can you show an example of this benchmark? Um, yes.
29:04 I tried to use something more. I don't know if your question goes into if it was too simple >> because my experience is for example if you look at the poster here the poster consists of six texts and seven images and some vector graphics and it depends on how many elements you have and how complicated there are and how many fonts you need. Let's see.
29:30 I can move this. Um, so the template I used look like this. So I tried to actually have an honest honest comparison. So this tried I tried to design it as a trade confirmation for a bank. So this is I I know you're more in the invoicing, right? We mean it's one page, a lot of text, still some lines. >> See if I somehow Yeah, exactly. And the mo most of the I think somewhere there I also put >> no image the top left is text >> um I think this was a PNG file.
30:34 Yeah. And these see if I Yeah. And kind of like do you see most of the data that was that probably changes was also like changed was randomized. So it also like most of the stuff you see for example the table had to be relayouted because like even the number sometimes the the results even had two pages based on how long the table were. >> Yeah. Okay, thanks.
31:13 >> Other questions? >> Yeah. >> Did you do comparison to Latte? Because like on the Docker container size, I can I couldn't agree more. It's a hell having mate in a Docker container. Did you run it speedwise against? >> No. Uh I but and kind of remember from my times using it back then I think the fastest you get is like 300 to 500 milliseconds and latte is speaking on that latte is actually if you say that it's not like you know which program to use because latte is huge they're like different CEK and lure latte so um
31:53 I think to do a comparison you can optimize it very heavily but so latte If I would build a PDF rendering engine back then five years ago, I would use latte because and I also saw at stock um stock agencies that they were lo using it like with MATLAB but I always felt it's it's not very modern because of the big compilation size and the error messaging that was orake in a way.
32:24 [snorts] Uh but yes, so um if you're for example interested, there are still the blog posts about it um on my website that talks a bit more about the um AWS Lambda setup and how to how you can compile a Rust program into an AWS Lambda function and yeah and also do the with the Terraform. Yeah. Any other questions? Yeah. >> Yeah. So, >> something that you need to pay like a license.
33:08 >> No, it's uh everything is open source. So, that's the that's the uh repo where most of the crates are. So, it's it's split into three crates. The main the main library that kind of builds around types. Then you have the registry which builds which works with all this manifest creating the hashes and then the last one is more or less just a topper where you have um a server but all of it is open source and uh like I mentioned it it heavily relies on the on the PDF rendering engine types.
33:49 Yeah. But um if you want to like have a go at it, feel free. Yeah. Any other questions? So are you working in an industry to >> Yes. >> Yeah. >> Start to wait. Yeah. And even like depending on how complicated it is with caching, you get a sub sub 10 milliseconds. >> Usually large. >> Yeah. >> But is was speed your main problem? very large >> to generate them in time.
34:52 >> Yes. >> Yeah. Yeah. Similar to the bank. Yeah. Um Yeah. Try it. Any other questions? Yeah. >> So you have like text in JSON form then you have a hash effect of it. You map it to a template and then you render the PDF. >> Yeah. >> That's the pipeline. >> Can you go in reverse? You the PDF when you get the template which was used, can you get the JSON back?
35:20 Like is that a possibility to come back to it or is that just >> you mean like uh you you rendered a bunch of PDFs and then the customer comes back to you with a PDF and says this can you check when it was rendered and with which what data? Yeah. >> Um if you have it digitally probably yes because you can imagine that at some point you you process or you um generate the PDF, right?
35:46 You could store this PDF or at least the hash in your in your bucket and then you would know which manifest was used to render it and from that you can derive all the rest. Yeah. But yeah, I think this is interesting for compliance areas where you want to know which which version was used. >> Yeah, wherever we do a lot of like PDF processing. So we need to figure out exactly what's in the PDF essentially.
36:17 We go back to a JSON format for that and then we create let's say more PDFs from that cycle that you need to do. So I'm just wondering like if you can let's say maintain similar hashes then maybe you can figure out what's the closest hash and say okay this is maybe the format that was used. Okay, that that's a bit different because um you need if it's visually just a little bit different, even if there's just something different that's not visible in the PDF, this would change the hash, right?
36:43 So, what you're talking more is like visual um comparison. I think we had a talk yesterday about it. Yeah. >> So, in my experience, when you do ask for specific layouts My question would be if you had to set some kind of boundaries I don't know if types does animation and I know PDF can do animation so I don't know if you want to go that far but I think for most layouts that we see in PDFs it's possible.
37:37 So um to maybe because we are obviously using types you could look at the examples they give most of them are um very so from scientific nature but you can do graphs you can do you can um bring in images so it's actually quite powerful I would say yes to your question if it's not very exotic Any other questions, remarks? Someone who wants to share his pain with documents.
38:14 Yeah. Not so far. Okay. Then that's also from my side. If you have no further questions. Okay. Lunch time. Early lunch. So yes, thanks. And I go back for those who who might want to take it.